code-stubs-ia32.cc revision 3fb3ca8c7ca439d408449a395897395c0faae8d1
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_IA32) 3180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "bootstrapper.h" 33257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#include "code-stubs.h" 3444f0eee88ff00398ff7f715fab053374d808c90dSteve Block#include "isolate.h" 35257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#include "jsregexp.h" 3680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "regexp-macro-assembler.h" 3780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsennamespace v8 { 3980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsennamespace internal { 4080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#define __ ACCESS_MASM(masm) 421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid ToNumberStub::Generate(MacroAssembler* masm) { 441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // The ToNumber stub takes one argument in eax. 45257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label check_heap_number, call_builtin; 463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &check_heap_number, Label::kNear); 471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&check_heap_number); 501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 5144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 5244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(Operand(ebx), Immediate(factory->heap_number_map())); 53257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &call_builtin, Label::kNear); 541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&call_builtin); 571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ pop(ecx); // Pop return address. 581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(eax); 591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(ecx); // Push return address. 601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); 611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 6480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewClosureStub::Generate(MacroAssembler* masm) { 6580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Create a new closure from the given function info in new 6680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // space. Set the context to the current context in esi. 6780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label gc; 6880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateInNewSpace(JSFunction::kSize, eax, ebx, ecx, &gc, TAG_OBJECT); 6980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 7080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the function info from the stack. 7180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 1 * kPointerSize)); 7280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 7344f0eee88ff00398ff7f715fab053374d808c90dSteve Block int map_index = strict_mode_ == kStrictMode 7444f0eee88ff00398ff7f715fab053374d808c90dSteve Block ? Context::STRICT_MODE_FUNCTION_MAP_INDEX 7544f0eee88ff00398ff7f715fab053374d808c90dSteve Block : Context::FUNCTION_MAP_INDEX; 7644f0eee88ff00398ff7f715fab053374d808c90dSteve Block 7780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compute the function map in the current global context and set that 7880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // as the map of the allocated object. 7980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 8080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset)); 8144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(ecx, Operand(ecx, Context::SlotOffset(map_index))); 8280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSObject::kMapOffset), ecx); 8380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 8480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Initialize the rest of the function. We don't have to update the 8580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // write barrier because the allocated object is in new space. 8644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 8744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(ebx, Immediate(factory->empty_fixed_array())); 8880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ebx); 8980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx); 9080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset), 9144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(factory->the_hole_value())); 9280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset), edx); 9380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSFunction::kContextOffset), esi); 9480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSFunction::kLiteralsOffset), ebx); 95b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSFunction::kNextFunctionLinkOffset), 9644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(factory->undefined_value())); 9780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 9880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Initialize the code pointer in the function to be the one 9980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // found in the shared function info object. 10080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); 10180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); 10280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSFunction::kCodeEntryOffset), edx); 10380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 10480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameter. 10580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(1 * kPointerSize); 10680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 10780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Create a new closure through the slower runtime call. 10880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&gc); 10980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ecx); // Temporarily remove return address. 11080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(edx); 11180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(esi); 11280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(edx); 11344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(Immediate(factory->false_value())); 11480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ecx); // Restore return address. 1158a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ TailCallRuntime(Runtime::kNewClosure, 3, 1); 11680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 11780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 11880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 11980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewContextStub::Generate(MacroAssembler* masm) { 12080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try to allocate the context in new space. 12180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label gc; 12280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int length = slots_ + Context::MIN_CONTEXT_SLOTS; 12380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, 12480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen eax, ebx, ecx, &gc, TAG_OBJECT); 12580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 12680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the function from the stack. 12780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esp, 1 * kPointerSize)); 12880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 12980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Setup the object header. 13044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 1313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(eax, HeapObject::kMapOffset), 1323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch factory->function_context_map()); 13380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, Context::kLengthOffset), 13480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(Smi::FromInt(length))); 13580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 13680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Setup the fixed slots. 1379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Set(ebx, Immediate(0)); // Set to NULL. 13880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx); 1393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), esi); 14080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(eax, Context::SlotOffset(Context::EXTENSION_INDEX)), ebx); 14180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy the global object from the previous context. 1433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 14480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx); 14580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 14680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Initialize the rest of the slots to undefined. 14744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(ebx, factory->undefined_value()); 14880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { 14980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(eax, Context::SlotOffset(i)), ebx); 15080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 15180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 15280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameter. 15380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(esi, Operand(eax)); 15480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(1 * kPointerSize); 15580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 15680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Need to collect. Call into runtime system. 15780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&gc); 1583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1); 15980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 16080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 16180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 16280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { 16380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack layout on entry: 16480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // 16580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // [esp + kPointerSize]: constant elements. 16680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // [esp + (2 * kPointerSize)]: literal index. 16780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // [esp + (3 * kPointerSize)]: literals array. 16880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 16980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // All sizes here are multiples of kPointerSize. 17080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0; 17180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int size = JSArray::kSize + elements_size; 17280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 17380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load boilerplate object into ecx and check if we need to create a 17480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // boilerplate. 17580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow_case; 17680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esp, 3 * kPointerSize)); 17780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, 2 * kPointerSize)); 17880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kPointerSize == 4); 17980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize == 1); 18080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 18180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size, 18280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize)); 18344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 18444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(ecx, factory->undefined_value()); 18580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &slow_case); 18680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 18780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 18880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const char* message; 18980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Handle<Map> expected_map; 19080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (mode_ == CLONE_ELEMENTS) { 19180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen message = "Expected (writable) fixed array"; 19244f0eee88ff00398ff7f715fab053374d808c90dSteve Block expected_map = factory->fixed_array_map(); 19380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 19480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS); 19580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen message = "Expected copy-on-write fixed array"; 19644f0eee88ff00398ff7f715fab053374d808c90dSteve Block expected_map = factory->fixed_cow_array_map(); 19780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 19880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ecx); 19980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); 20080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), expected_map); 20180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Assert(equal, message); 20280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ecx); 20380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 20480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 20580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate both the JS array and the elements array in one big 20680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // allocation. This avoids multiple limit checks. 20780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateInNewSpace(size, eax, ebx, edx, &slow_case, TAG_OBJECT); 20880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 20980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy the JS array part. 21080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = 0; i < JSArray::kSize; i += kPointerSize) { 21180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if ((i != JSArray::kElementsOffset) || (length_ == 0)) { 21280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(ecx, i)); 21380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, i), ebx); 21480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 21580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 21680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 21780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (length_ > 0) { 21880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get hold of the elements array of the boilerplate and setup the 21980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // elements pointer in the resulting object. 22080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); 22180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(edx, Operand(eax, JSArray::kSize)); 22280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSArray::kElementsOffset), edx); 22380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 22480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy the elements array. 22580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = 0; i < elements_size; i += kPointerSize) { 22680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(ecx, i)); 22780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(edx, i), ebx); 22880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 22980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 23080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 23180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameters. 23280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 23380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 23480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow_case); 23580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); 23680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 23780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 23880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch// The stub returns zero for false, and a non-zero value for true. 24080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ToBooleanStub::Generate(MacroAssembler* masm) { 241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label false_result, true_result, not_string; 242257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Factory* factory = masm->isolate()->factory(); 2433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const Register map = edx; 2443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 2453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(eax, Operand(esp, 1 * kPointerSize)); 246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // undefined -> false 248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(eax, factory->undefined_value()); 249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &false_result); 250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Boolean -> its value 252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(eax, factory->false_value()); 253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &false_result); 2543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(eax, factory->true_value()); 2553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(equal, &true_result); 256257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 257257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Smis: 0 -> false, all other -> true 258257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(eax, Operand(eax)); 259257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &false_result); 2603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &true_result); 26180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 'null' -> false. 26344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, factory->null_value()); 264257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &false_result, Label::kNear); 26580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Get the map of the heap object. 2673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(map, FieldOperand(eax, HeapObject::kMapOffset)); 26880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Undetectable -> false. 2703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ test_b(FieldOperand(map, Map::kBitFieldOffset), 27180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1 << Map::kIsUndetectable); 272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &false_result, Label::kNear); 27380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // JavaScript object -> true. 2753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); 276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &true_result, Label::kNear); 27780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // String value -> false iff empty. 2793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); 280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, ¬_string, Label::kNear); 28180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(eax, String::kLengthOffset), Immediate(0)); 282257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &false_result, Label::kNear); 283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&true_result, Label::kNear); 28480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 28580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_string); 2863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // HeapNumber -> false iff +0, -0, or NaN. 2873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(map, factory->heap_number_map()); 288257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &true_result, Label::kNear); 28980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fldz(); 29080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); 29180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ FCmp(); 292257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &false_result, Label::kNear); 29380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fall through to |true_result|. 29480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Return 1/0 for true/false in tos_. 29680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&true_result); 2973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(tos_, 1); 29880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(1 * kPointerSize); 29980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&false_result); 3003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(tos_, 0); 30180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(1 * kPointerSize); 30280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 30380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 30480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3058b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochclass FloatingPointHelper : public AllStatic { 3068b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch public: 3078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch enum ArgLocation { 3088b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch ARGS_ON_STACK, 3098b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch ARGS_IN_REGISTERS 3108b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch }; 31180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3128b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Code pattern for loading a floating point value. Input value must 3138b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // be either a smi or a heap number object (fp value). Requirements: 3148b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operand in register number. Returns operand as floating point number 3158b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // on FPU stack. 3168b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadFloatOperand(MacroAssembler* masm, Register number); 31780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3188b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Code pattern for loading floating point values. Input values must 3198b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // be either smi or heap number objects (fp values). Requirements: 3208b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax. 3218b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Returns operands as floating point numbers on FPU stack. 3228b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadFloatOperands(MacroAssembler* masm, 3238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register scratch, 3248b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch ArgLocation arg_location = ARGS_ON_STACK); 32580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Similar to LoadFloatOperand but assumes that both operands are smis. 3278b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Expects operands in edx, eax. 3288b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadFloatSmis(MacroAssembler* masm, Register scratch); 329b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Test if operands are smi or number objects (fp). Requirements: 3318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operand_1 in eax, operand_2 in edx; falls through on float 3328b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operands, jumps to the non_float label otherwise. 3338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void CheckFloatOperands(MacroAssembler* masm, 3348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* non_float, 3358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register scratch); 336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Checks that the two floating point numbers on top of the FPU stack 3388b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // have int32 values. 3398b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void CheckFloatOperandsAreInt32(MacroAssembler* masm, 3408b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* non_int32); 341b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3428b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Takes the operands in edx and eax and loads them as integers in eax 3438b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // and ecx. 3448b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadUnknownsAsIntegers(MacroAssembler* masm, 3458b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch bool use_sse3, 3468b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* operand_conversion_failure); 347b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3488b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Must only be called after LoadUnknownsAsIntegers. Assumes that the 3498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operands are pushed on the stack, and that their conversions to int32 3508b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // are in eax and ecx. Checks that the original numbers were in the int32 3518b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // range. 3528b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void CheckLoadedIntegersWereInt32(MacroAssembler* masm, 3538b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch bool use_sse3, 3548b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* not_int32); 355b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3568b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Assumes that operands are smis or heap numbers and loads them 3578b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // into xmm0 and xmm1. Operands are in edx and eax. 3588b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Leaves operands unchanged. 3598b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadSSE2Operands(MacroAssembler* masm); 360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3618b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Test if operands are numbers (smi or HeapNumber objects), and load 3628b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // them into xmm0 and xmm1 if they are. Jump to label not_numbers if 3638b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // either operand is not a number. Operands are in edx and eax. 3648b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Leaves operands unchanged. 3658b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers); 366b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3678b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Similar to LoadSSE2Operands but assumes that both operands are smis. 3688b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Expects operands in edx, eax. 3698b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadSSE2Smis(MacroAssembler* masm, Register scratch); 370b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Checks that the two floating point numbers loaded into xmm0 and xmm1 372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // have int32 values. 373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch static void CheckSSE2OperandsAreInt32(MacroAssembler* masm, 374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* non_int32, 375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch); 376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}; 377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Get the integer part of a heap number. Surprisingly, all this bit twiddling 380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// is faster than using the built-in instructions on floating point registers. 381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the 382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// trashed registers. 383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void IntegerConvert(MacroAssembler* masm, 384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register source, 385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch bool use_sse3, 386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* conversion_failure) { 387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); 388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done, right_exponent, normal_exponent; 389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch = ebx; 390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch2 = edi; 391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get exponent word. 392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); 393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get exponent alone in scratch2. 394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch2, scratch); 395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(scratch2, HeapNumber::kExponentMask); 396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (use_sse3) { 397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CpuFeatures::Scope scope(SSE3); 398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check whether the exponent is too big for a 64 bit signed integer. 399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch static const uint32_t kTooBigExponent = 400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; 401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(Operand(scratch2), Immediate(kTooBigExponent)); 402257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(greater_equal, conversion_failure); 403257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Load x87 register with heap number. 404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); 405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Reserve space for 64 bit answer. 406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sub(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. 407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Do conversion, which cannot fail because we checked the exponent. 408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fisttp_d(Operand(esp, 0)); 409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, Operand(esp, 0)); // Load low word of answer into ecx. 410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. 411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Load ecx with zero. We use this either for the final shift or 413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // for the answer. 414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xor_(ecx, Operand(ecx)); 415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check whether the exponent matches a 32 bit signed int that cannot be 416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // represented by a Smi. A non-smi 32 bit integer is 1.xxx * 2^30 so the 417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // exponent is 30 (biased). This is the exponent that we are fastest at and 418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // also the highest exponent we can handle here. 419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const uint32_t non_smi_exponent = 420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; 421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(Operand(scratch2), Immediate(non_smi_exponent)); 422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If we have a match of the int32-but-not-Smi exponent then skip some 423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // logic. 424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &right_exponent); 425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If the exponent is higher than that then go to slow case. This catches 426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // numbers that don't fit in a signed int32, infinities and NaNs. 427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(less, &normal_exponent); 428257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch { 430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle a big exponent. The only reason we have this code is that the 431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // >>> operator has a tendency to generate numbers with an exponent of 31. 432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const uint32_t big_non_smi_exponent = 433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift; 434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(Operand(scratch2), Immediate(big_non_smi_exponent)); 435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, conversion_failure); 436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We have the big exponent, typically from >>>. This means the number is 437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // in the range 2^31 to 2^32 - 1. Get the top bits of the mantissa. 438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch2, scratch); 439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(scratch2, HeapNumber::kMantissaMask); 440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Put back the implicit 1. 441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ or_(scratch2, 1 << HeapNumber::kExponentShift); 442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Shift up the mantissa bits to take up the space the exponent used to 443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // take. We just orred in the implicit bit so that took care of one and 444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // we want to use the full unsigned range so we subtract 1 bit from the 445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // shift distance. 446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1; 447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shl(scratch2, big_shift_distance); 448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get the second half of the double. 449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset)); 450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Shift down 21 bits to get the most significant 11 bits or the low 451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // mantissa word. 452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(ecx, 32 - big_shift_distance); 453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ or_(ecx, Operand(scratch2)); 454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We have the answer in ecx, but we may need to negate it. 455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(scratch, Operand(scratch)); 456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(positive, &done); 457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ neg(ecx); 458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done); 459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&normal_exponent); 462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Exponent word in scratch, exponent part of exponent word in scratch2. 463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Zero in ecx. 464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We know the exponent is smaller than 30 (biased). If it is less than 465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie 466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // it rounds to zero. 467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const uint32_t zero_exponent = 468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift; 469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sub(Operand(scratch2), Immediate(zero_exponent)); 470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // ecx already has a Smi zero. 471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(less, &done); 472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We have a shifted exponent between 0 and 30 in scratch2. 474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(scratch2, HeapNumber::kExponentShift); 475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, Immediate(30)); 476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sub(ecx, Operand(scratch2)); 477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&right_exponent); 479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Here ecx is the shift, scratch is the exponent word. 480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get the top bits of the mantissa. 481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(scratch, HeapNumber::kMantissaMask); 482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Put back the implicit 1. 483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ or_(scratch, 1 << HeapNumber::kExponentShift); 484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Shift up the mantissa bits to take up the space the exponent used to 485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // take. We have kExponentShift + 1 significant bits int he low end of the 486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // word. Shift them to the top bits. 487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2; 488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shl(scratch, shift_distance); 489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get the second half of the double. For some exponents we don't 490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // actually need this because the bits get shifted out again, but 491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // it's probably slower to test than just to do it. 492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset)); 493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Shift down 22 bits to get the most significant 10 bits or the low 494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // mantissa word. 495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(scratch2, 32 - shift_distance); 496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ or_(scratch2, Operand(scratch)); 497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Move down according to the exponent. 498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr_cl(scratch2); 499257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Now the unsigned answer is in scratch2. We need to move it to ecx and 500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // we may need to fix the sign. 501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label negative; 502257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xor_(ecx, Operand(ecx)); 503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset)); 504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(greater, &negative, Label::kNear); 505257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, scratch2); 506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 507257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&negative); 508257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sub(ecx, Operand(scratch2)); 509257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&done); 510257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid UnaryOpStub::PrintName(StringStream* stream) { 515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const char* op_name = Token::Name(op_); 516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const char* overwrite_name = NULL; // Make g++ happy. 517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (mode_) { 518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; 519257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; 520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 5213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("UnaryOpStub_%s_%s_%s", 5223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch op_name, 5233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch overwrite_name, 5243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch UnaryOpIC::GetName(operand_type_)); 525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 526257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 528257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 529257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::Generate(MacroAssembler* masm) { 530257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (operand_type_) { 531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::UNINITIALIZED: 532257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 533257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 534257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::SMI: 535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStub(masm); 536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 537257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::HEAP_NUMBER: 538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStub(masm); 539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 540257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::GENERIC: 541257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStub(masm); 542257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 543257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 544257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 545257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 547257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 548257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(ecx); // Save return address. 5493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 5503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(eax); // the operand 551257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(Immediate(Smi::FromInt(op_))); 5523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(Immediate(Smi::FromInt(mode_))); 553257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(Immediate(Smi::FromInt(operand_type_))); 554257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 555257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(ecx); // Push return address. 556257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 557257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Patch the caller to an appropriate specialized stub and return the 558257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // operation result to the caller of the stub. 559257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ TailCallExternalReference( 5603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1); 561257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 562257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 565257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 566257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 567257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 568257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStubSub(masm); 569257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 570257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 571257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStubBitNot(masm); 572257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 573257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 574257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 575257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 576257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 577257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 578257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 579257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) { 580257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, undo, slow; 581257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, 582257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::kNear, Label::kNear, Label::kNear); 583257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&undo); 584257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeUndo(masm); 585257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 586257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 587257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 588257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 589257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 590257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 591257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) { 592257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi; 593257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi); 594257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 595257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 596257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 597257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 598257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 599257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, 600257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* non_smi, 601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* undo, 602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* slow, 603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance non_smi_near, 604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance undo_near, 605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance slow_near) { 606257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check whether the value is a smi. 6073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, non_smi, non_smi_near); 608257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 609257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We can't handle -0 with smis, so use a type transition for that case. 610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(eax, Operand(eax)); 611257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, slow, slow_near); 612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Try optimistic subtraction '0 - value', saving operand in eax for undo. 614257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edx, Operand(eax)); 615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(0)); 616257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sub(eax, Operand(edx)); 617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(overflow, undo, undo_near); 618257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 621257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeBitNot( 623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 624257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* non_smi, 625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance non_smi_near) { 626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check whether the value is a smi. 6273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, non_smi, non_smi_near); 628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Flip bits and revert inverted smi-tag. 630257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ not_(eax); 631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(eax, ~kSmiTagMask); 632257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 633257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) { 637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(eax, Operand(edx)); 638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 641257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 642257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 643257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStubSub(masm); 646257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 647257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStubBitNot(masm); 649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 650257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 651257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) { 657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, undo, slow, call_builtin; 658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &non_smi, &undo, &call_builtin, Label::kNear); 659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeSub(masm, &slow); 661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&undo); 662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeUndo(masm); 663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_builtin); 666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubBitNot( 671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm) { 672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow; 673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); 674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeBitNot(masm, &slow); 676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, 682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* slow) { 683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); 684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(edx, masm->isolate()->factory()->heap_number_map()); 685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, slow); 686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (mode_ == UNARY_OVERWRITE) { 688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset), 689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Immediate(HeapNumber::kSignMask)); // Flip sign. 690257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 691257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edx, Operand(eax)); 692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // edx: operand 693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label slow_allocate_heapnumber, heapnumber_allocated; 695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber); 696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&heapnumber_allocated); 697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow_allocate_heapnumber); 699257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ EnterInternalFrame(); 700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(edx); 701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallRuntime(Runtime::kNumberAlloc, 0); 702257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(edx); 703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ LeaveInternalFrame(); 704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&heapnumber_allocated); 706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // eax: allocated 'empty' number 707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); 708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xor_(ecx, HeapNumber::kSignMask); // Flip sign. 709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx); 710257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset)); 711257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); 712257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 713257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 714257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 715257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 716257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm, 718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* slow) { 719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); 720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(edx, masm->isolate()->factory()->heap_number_map()); 721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, slow); 722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Convert the heap number in eax to an untagged integer in ecx. 724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), slow); 725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Do the bitwise operation and check if the result fits in a smi. 727257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label try_float; 728257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ not_(ecx); 729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(ecx, 0xc0000000); 730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(sign, &try_float, Label::kNear); 731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Tag the result as a smi and we're done. 733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTagSize == 1); 734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(eax, Operand(ecx, times_2, kSmiTag)); 735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Try to store the result in a heap number. 738257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&try_float); 739257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (mode_ == UNARY_NO_OVERWRITE) { 740257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label slow_allocate_heapnumber, heapnumber_allocated; 741257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ebx, eax); 742257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ AllocateHeapNumber(eax, edx, edi, &slow_allocate_heapnumber); 743257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&heapnumber_allocated); 744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 745257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow_allocate_heapnumber); 746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ EnterInternalFrame(); 747257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Push the original HeapNumber on the stack. The integer value can't 748257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // be stored since it's untagged and not in the smi range (so we can't 749257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // smi-tag it). We'll recalculate the value after the GC instead. 750257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(ebx); 751257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallRuntime(Runtime::kNumberAlloc, 0); 752257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // New HeapNumber is in eax. 753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(edx); 754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ LeaveInternalFrame(); 755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // IntegerConvert uses ebx and edi as scratch registers. 756257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // This conversion won't go slow-case. 757257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch IntegerConvert(masm, edx, CpuFeatures::IsSupported(SSE3), slow); 758257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ not_(ecx); 759257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 760257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&heapnumber_allocated); 761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 763257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 764257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cvtsi2sd(xmm0, Operand(ecx)); 765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(ecx); 768257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fild_s(Operand(esp, 0)); 769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(ecx); 770257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 771257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) { 778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 779257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 780257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStubSub(masm); 781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 782257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 783257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStubBitNot(masm); 784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 785257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 787257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 789257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) { 792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, undo, slow; 793257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, Label::kNear); 794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 795257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeSub(masm, &slow); 796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&undo); 797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeUndo(masm); 798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 799257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) { 804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow; 805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); 806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeBitNot(masm, &slow); 808257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 809257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 810257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) { 814257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle the slow case by jumping to the corresponding JavaScript builtin. 815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(ecx); // pop return address. 816257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(eax); 817257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(ecx); // push return address 818257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 819257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 820257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION); 821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); 824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 825257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 826257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 829b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 830b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 832b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(ecx); // Save return address. 833b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(edx); 834b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(eax); 835b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Left and right arguments are now on top. 836b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Push this stub's key. Although the operation and the type info are 837b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // encoded into the key, the encoding is opaque, so push them too. 838b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(MinorKey()))); 839b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(op_))); 840b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(operands_type_))); 841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(ecx); // Push return address. 843b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 844b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Patch the caller to an appropriate specialized stub and return the 845b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // operation result to the caller of the stub. 846b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TailCallExternalReference( 847257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ExternalReference(IC_Utility(IC::kBinaryOp_Patch), 84844f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()), 849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5, 850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1); 851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// Prepare for a type transition runtime call when the args are already on 855b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// the stack, under the return address. 856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) { 857b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(ecx); // Save return address. 858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Left and right arguments are already on top of the stack. 859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Push this stub's key. Although the operation and the type info are 860b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // encoded into the key, the encoding is opaque, so push them too. 861b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(MinorKey()))); 862b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(op_))); 863b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(operands_type_))); 864b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 865b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(ecx); // Push return address. 866b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 867b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Patch the caller to an appropriate specialized stub and return the 868b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // operation result to the caller of the stub. 869b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TailCallExternalReference( 870257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ExternalReference(IC_Utility(IC::kBinaryOp_Patch), 87144f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()), 872b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5, 873b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1); 874b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 875b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 876b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::Generate(MacroAssembler* masm) { 878b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (operands_type_) { 879257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::UNINITIALIZED: 880b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 881b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 882257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::SMI: 883b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateSmiStub(masm); 884b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::INT32: 886b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateInt32Stub(masm); 887b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::HEAP_NUMBER: 889b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapNumberStub(masm); 890b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::ODDBALL: 89244f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateOddballStub(masm); 89344f0eee88ff00398ff7f715fab053374d808c90dSteve Block break; 894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::BOTH_STRING: 895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateBothStringStub(masm); 896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::STRING: 898b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateStringStub(masm); 899b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::GENERIC: 901b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateGeneric(masm); 902b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 903b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 904b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 905b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 906b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 907b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 908b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 9093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid BinaryOpStub::PrintName(StringStream* stream) { 910b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const char* op_name = Token::Name(op_); 911b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const char* overwrite_name; 912b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode_) { 913b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: overwrite_name = "Alloc"; break; 914b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; 915b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; 916b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: overwrite_name = "UnknownOverwrite"; break; 917b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 9183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("BinaryOpStub_%s_%s_%s", 9193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch op_name, 9203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch overwrite_name, 9213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch BinaryOpIC::GetName(operands_type_)); 922b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 923b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 924b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiCode( 926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 927b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* slow, 928b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { 929b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 1. Move arguments into edx, eax except for DIV and MOD, which need the 930b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // dividend in eax and edx free for the division. Use eax, ebx for those. 931b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment load_comment(masm, "-- Load arguments"); 932b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register left = edx; 933b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register right = eax; 934b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ == Token::DIV || op_ == Token::MOD) { 935b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch left = eax; 936b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch right = ebx; 937b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, eax); 938b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, edx); 939b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 940b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 941b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 942b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 2. Prepare the smi check of both operands by oring them together. 943b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment smi_check_comment(masm, "-- Smi check arguments"); 944b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_smis; 945b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register combined = ecx; 946b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(!left.is(combined) && !right.is(combined)); 947b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 948b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 949b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Perform the operation into eax and smi check the result. Preserve 950b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax in case the result is not a smi. 951b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(!left.is(ecx) && !right.is(ecx)); 952b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, right); 953b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ or_(right, Operand(left)); // Bitwise or is commutative. 954b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch combined = right; 955b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 956b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 957b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 958b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 959b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 960b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 961b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 962b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 963b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 964b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(combined, right); 965b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ or_(combined, Operand(left)); 966b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 967b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 968b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 969b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 970b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 971b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Move the right operand into ecx for the shift operation, use eax 972b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // for the smi check register. 973b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(!left.is(ecx) && !right.is(ecx)); 974b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, right); 975b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ or_(right, Operand(left)); 976b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch combined = right; 977b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 978b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 979b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 980b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 981b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 982b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 983b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 3. Perform the smi check of the operands. 984b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTag == 0); // Adjust zero check if not the case. 9853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(combined, ¬_smis); 986b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 987b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 4. Operands are both smis, perform the operation leaving the result in 988b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax and check the result if necessary. 989b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment perform_smi(masm, "-- Perform smi operation"); 990b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label use_fp_on_smis; 991b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 992b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 993b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Nothing to do. 994b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 995b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 996b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 997b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(right.is(eax)); 998b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ xor_(right, Operand(left)); // Bitwise xor is commutative. 999b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1000b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1001b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1002b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(right.is(eax)); 1003b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ and_(right, Operand(left)); // Bitwise and is commutative. 1004b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1005b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1006b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1007b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Remove tags from operands (but keep sign). 1008b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(left); 1009b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(ecx); 1010b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Perform the operation. 1011b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ shl_cl(left); 1012b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check that the *signed* result fits in a smi. 1013b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(left, 0xc0000000); 1014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(sign, &use_fp_on_smis); 1015b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag the result and store it in register eax. 1016b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(left); 1017b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, left); 1018b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1019b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1020b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1021b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Remove tags from operands (but keep sign). 1022b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(left); 1023b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(ecx); 1024b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Perform the operation. 1025b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sar_cl(left); 1026b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag the result and store it in register eax. 1027b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(left); 1028b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, left); 1029b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1030b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1031b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1032b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Remove tags from operands (but keep sign). 1033b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(left); 1034b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(ecx); 1035b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Perform the operation. 1036b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ shr_cl(left); 1037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check that the *unsigned* result fits in a smi. 1038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Neither of the two high-order bits can be set: 1039b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // - 0x80000000: high bit would be lost when smi tagging. 1040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // - 0x40000000: this number would convert to negative when 1041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Smi tagging these two cases can only happen with shifts 1042b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // by 0 or 1 when handed a valid smi. 1043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(left, Immediate(0xc0000000)); 1044257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &use_fp_on_smis); 1045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag the result and store it in register eax. 1046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(left); 1047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, left); 1048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(right.is(eax)); 1052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(right, Operand(left)); // Addition is commutative. 1053257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(overflow, &use_fp_on_smis); 1054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1057b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(left, Operand(right)); 1058257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(overflow, &use_fp_on_smis); 1059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, left); 1060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the smi tag is 0 we can just leave the tag on one operand. 1064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTag == 0); // Adjust code below if not the case. 1065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // We can't revert the multiplication if the result is not a smi 1066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // so save the right operand. 1067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, right); 1068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Remove tag from one of the operands (but keep sign). 1069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(right); 1070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Do multiplication. 1071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ imul(right, Operand(left)); // Multiplication is commutative. 1072257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(overflow, &use_fp_on_smis); 1073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for negative zero result. Use combined = left | right. 1074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ NegativeZeroTest(right, combined, &use_fp_on_smis); 1075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1077b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1078b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // We can't revert the division if the result is not a smi so 1079b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // save the left operand. 1080b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edi, left); 1081b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for 0 divisor. 1082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(right, Operand(right)); 1083257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &use_fp_on_smis); 1084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Sign extend left into edx:eax. 1085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(left.is(eax)); 1086b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cdq(); 1087b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Divide edx:eax by right. 1088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ idiv(right); 1089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for the corner case of dividing the most negative smi by 1090b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // -1. We cannot use the overflow flag, since it is not set by idiv 1091b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // instruction. 1092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); 1093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(eax, 0x40000000); 1094b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(equal, &use_fp_on_smis); 1095b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for negative zero result. Use combined = left | right. 1096b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ NegativeZeroTest(eax, combined, &use_fp_on_smis); 1097b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check that the remainder is zero. 1098b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(edx, Operand(edx)); 1099b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &use_fp_on_smis); 1100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag the result and store it in register eax. 1101b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(eax); 1102b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1104b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for 0 divisor. 1106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(right, Operand(right)); 1107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, ¬_smis); 1108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Sign extend left into edx:eax. 1110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(left.is(eax)); 1111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cdq(); 1112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Divide edx:eax by right. 1113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ idiv(right); 1114b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for negative zero result. Use combined = left | right. 1115b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ NegativeZeroTest(edx, combined, slow); 1116b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Move remainder to register eax. 1117b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, edx); 1118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1120b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 5. Emit return of result in eax. Some operations have registers pushed. 1125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1130b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1136b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); 1140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1141b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1142b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1143b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1144b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1145b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 6. For some operations emit inline code to perform floating point 1146b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // operations on known smis (e.g., if the result of the operation 1147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // overflowed the smi range). 1148b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (allow_heapnumber_results == NO_HEAPNUMBER_RESULTS) { 1149b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&use_fp_on_smis); 1150b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1151b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Undo the effects of some operations, and some register moves. 1152b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1153b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // The arguments are saved on the stack, and only used from there. 1154b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1155b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1156b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Revert right = right + left. 1157b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(right, Operand(left)); 1158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1159b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1160b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Revert left = left - right. 1161b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(left, Operand(right)); 1162b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Right was clobbered but a copy is in ebx. 1165b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(right, ebx); 1166b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1167b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1168b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Left was clobbered but a copy is in edi. Right is in ebx for 1169b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // division. They should be in eax, ebx for jump to not_smi. 1170b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, edi); 1171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1172b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // No other operators jump to use_fp_on_smis. 1174b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1175b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1176b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(¬_smis); 1177b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1178b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS); 1179b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SHL: 1181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SHR: { 1182b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment perform_float(masm, "-- Perform float operation on smis"); 1183b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&use_fp_on_smis); 1184b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Result we want is in left == edx, so we can put the allocated heap 1185b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // number in eax. 1186b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, ecx, ebx, slow); 1187b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Store the result in the HeapNumber and return. 1188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // It's OK to overwrite the arguments on the stack because we 1189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // are about to return. 1190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (op_ == Token::SHR) { 1191b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), left); 1192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(Operand(esp, 2 * kPointerSize), Immediate(0)); 1193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fild_d(Operand(esp, 1 * kPointerSize)); 1194b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 1196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT_EQ(Token::SHL, op_); 1197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cvtsi2sd(xmm0, Operand(left)); 1200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 1202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), left); 1203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fild_s(Operand(esp, 1 * kPointerSize)); 1204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 1206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 1208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 1209b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1210b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1211b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1212b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1213b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1214b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: { 1215b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment perform_float(masm, "-- Perform float operation on smis"); 1216b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&use_fp_on_smis); 1217b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Restore arguments to edx, eax. 1218b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1219b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1220b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Revert right = right + left. 1221b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(right, Operand(left)); 1222b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1224b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Revert left = left - right. 1225b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(left, Operand(right)); 1226b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1227b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1228b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Right was clobbered but a copy is in ebx. 1229b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(right, ebx); 1230b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1231b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1232b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Left was clobbered but a copy is in edi. Right is in ebx for 1233b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // division. 1234b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, edi); 1235b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, right); 1236b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1237b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1238b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1239b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1240b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(ecx, ebx, no_reg, slow); 12418b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1242b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1243b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Smis(masm, ebx); 1244b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1245b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ addsd(xmm0, xmm1); break; 1246b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ subsd(xmm0, xmm1); break; 1247b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ mulsd(xmm0, xmm1); break; 1248b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ divsd(xmm0, xmm1); break; 1249b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1250b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1251b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0); 1252b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // SSE2 not available, use FPU. 1253b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadFloatSmis(masm, ebx); 1254b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1255b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ faddp(1); break; 1256b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ fsubp(1); break; 1257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ fmulp(1); break; 1258b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ fdivp(1); break; 1259b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1260b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset)); 1262b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, ecx); 1264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1265b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1266b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1267b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1268b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1269b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1270b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1271b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1272b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1273b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 7. Non-smi operands, fall out to the non-smi code with the operands in 1274b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // edx and eax. 1275b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment done_comment(masm, "-- Enter non-smi code"); 1276b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_smis); 1277b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1278b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1279b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1280b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1281b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1282b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Right operand is saved in ecx and eax was destroyed by the smi 1283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // check. 1284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, ecx); 1285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Operands are in eax, ebx at this point. 1290b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, eax); 1291b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, ebx); 1292b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1293b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1294b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1295b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1297b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1298b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1299b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1300257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 1301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label call_runtime; 1302b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1306b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1307b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1309b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1310b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1311b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1312b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1313b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1314b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1315b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1316b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1317b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1318b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1319b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1320b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1321b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1322257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (result_type_ == BinaryOpIC::UNINITIALIZED || 1323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch result_type_ == BinaryOpIC::SMI) { 1324b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateSmiCode(masm, &call_runtime, NO_HEAPNUMBER_RESULTS); 1325b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1326b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 1327b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1328b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&call_runtime); 1329b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1330b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1331b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1332b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1333b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1334b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 1335b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1337b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1338b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1339b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1340b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1341b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1342b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1343b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransitionWithSavedArgs(masm); 1344b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1345b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1346b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1347b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1348b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1349b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1350b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { 1352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(operands_type_ == BinaryOpIC::STRING); 1353b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(op_ == Token::ADD); 13541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Try to add arguments as strings, otherwise, transition to the generic 1355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // BinaryOpIC type. 13561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateAddStrings(masm); 1357b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 1358b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1359b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { 1362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label call_runtime; 1363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); 1364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(op_ == Token::ADD); 1365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If both arguments are strings, call the string add stub. 1366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Otherwise, do a transition. 1367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 1369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = edx; 1370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = eax; 1371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Test if left operand is a string. 13733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(left, &call_runtime); 1374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); 1375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &call_runtime); 1376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Test if right operand is a string. 13783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(right, &call_runtime); 1379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); 1380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &call_runtime); 1381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); 1383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateRegisterArgsPush(masm); 1384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ TailCallStub(&string_add_stub); 1385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_runtime); 1387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 1388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { 1392b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label call_runtime; 1393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(operands_type_ == BinaryOpIC::INT32); 1394b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1395b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Floating point case. 1396b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1397b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1398b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1399b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1400b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: { 1401b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 1402b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_int32; 14038b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1404b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1405b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 1406b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); 1407b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1408b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ addsd(xmm0, xmm1); break; 1409b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ subsd(xmm0, xmm1); break; 1410b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ mulsd(xmm0, xmm1); break; 1411b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ divsd(xmm0, xmm1); break; 1412b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1413b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1414b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check result type if it is currently Int32. 1415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (result_type_ <= BinaryOpIC::INT32) { 1416b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvttsd2si(ecx, Operand(xmm0)); 1417b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm2, Operand(ecx)); 1418b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm0, xmm2); 1419b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, ¬_int32); 1420b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(carry, ¬_int32); 1421b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1422b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &call_runtime); 1423b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1424b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1425b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // SSE2 not available, use FPU. 1426b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); 1427b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadFloatOperands( 1428b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch masm, 1429b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ecx, 1430b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::ARGS_IN_REGISTERS); 1431b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckFloatOperandsAreInt32(masm, ¬_int32); 1432b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1433b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ faddp(1); break; 1434b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ fsubp(1); break; 1435b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ fmulp(1); break; 1436b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ fdivp(1); break; 1437b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1438b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1439b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label after_alloc_failure; 1440b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &after_alloc_failure); 1441b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1442b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1443b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&after_alloc_failure); 1444b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ffree(); 1445b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&call_runtime); 1446b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1447b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1448b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 1449b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_int32); 1450b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 1451b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1452b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1453b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1454b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: { 1455b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // For MOD we go directly to runtime in the non-smi case. 1456b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1457b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1458b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1459b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1460b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1461b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1462b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1463b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: { 1464b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1465b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 1466b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_int32; 1467b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label non_smi_result; 1468b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch /* { 1469b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1470b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 1471b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); 1472b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch }*/ 1473b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadUnknownsAsIntegers(masm, 1474b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch use_sse3_, 1475b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ¬_floats); 1476b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_, 1477b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ¬_int32); 1478b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1479b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; 1480b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; 1481b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; 1482b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: __ sar_cl(eax); break; 1483b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: __ shl_cl(eax); break; 1484b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: __ shr_cl(eax); break; 1485b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1486b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1487b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ == Token::SHR) { 1488b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result is non-negative and fits in a smi. 1489b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(eax, Immediate(0xc0000000)); 1490b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &call_runtime); 1491b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1492b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result fits in a smi. 1493b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(eax, 0xc0000000); 1494b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(negative, &non_smi_result); 1495b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1496b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag smi result and return. 1497b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(eax); 1498b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1499b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1500b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // All ops except SHR return a signed int32 that we load in 1501b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // a HeapNumber. 1502b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ != Token::SHR) { 1503b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&non_smi_result); 1504b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number if needed. 1505b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, Operand(eax)); // ebx: result 1506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label skip_allocation; 1507b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode_) { 1508b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: 1509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: 1510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the operand was an object, we skip the 1511b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 1512b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 1513b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1 * kPointerSize : 2 * kPointerSize)); 15143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 1515b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fall through! 1516b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: 1517b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 1518b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 1519b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1520b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1521b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1522b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Store the result in the HeapNumber and return. 15238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1524b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1525b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm0, Operand(ebx)); 1526b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1527b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1528b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ebx); 1529b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fild_s(Operand(esp, 1 * kPointerSize)); 1530b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1534b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 1536b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_int32); 1537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransitionWithSavedArgs(masm); 1538b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1539b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1540b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); break; 1541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If an allocation fails, or SHR or MOD hit a hard case, 1544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // use the runtime system to get the correct result. 1545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&call_runtime); 1546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1549b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1550b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 1551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1552b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 1555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 1559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 1563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1566b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 1567b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 1570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 1573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1575b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 1576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1577b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1578b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 1579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1580b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1581b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 1582b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1583b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 1585b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1586b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1587b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1588b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1589b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1590b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1591b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1592257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { 159344f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (op_ == Token::ADD) { 159444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Handle string addition here, because it is the only operation 159544f0eee88ff00398ff7f715fab053374d808c90dSteve Block // that does not do a ToNumber conversion on the operands. 159644f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateAddStrings(masm); 159744f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 159844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 1599257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Factory* factory = masm->isolate()->factory(); 1600257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 160144f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Convert odd ball arguments to numbers. 1602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label check, done; 1603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(edx, factory->undefined_value()); 1604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &check, Label::kNear); 160544f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (Token::IsBitOp(op_)) { 160644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ xor_(edx, Operand(edx)); 160744f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 1608257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edx, Immediate(factory->nan_value())); 160944f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 1610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 161144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&check); 1612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(eax, factory->undefined_value()); 1613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &done, Label::kNear); 161444f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (Token::IsBitOp(op_)) { 161544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ xor_(eax, Operand(eax)); 161644f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 1617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(eax, Immediate(factory->nan_value())); 161844f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 161944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&done); 162044f0eee88ff00398ff7f715fab053374d808c90dSteve Block 162144f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateHeapNumberStub(masm); 162244f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 162344f0eee88ff00398ff7f715fab053374d808c90dSteve Block 162444f0eee88ff00398ff7f715fab053374d808c90dSteve Block 1625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 1626b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label call_runtime; 1627b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1628b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Floating point case. 1629b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1630b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1632b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1633b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: { 1634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 16358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1636b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1637b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 1638b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1639b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1640b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ addsd(xmm0, xmm1); break; 1641b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ subsd(xmm0, xmm1); break; 1642b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ mulsd(xmm0, xmm1); break; 1643b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ divsd(xmm0, xmm1); break; 1644b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1645b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1646b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &call_runtime); 1647b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1648b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1649b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // SSE2 not available, use FPU. 1650b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); 1651b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadFloatOperands( 1652b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch masm, 1653b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ecx, 1654b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::ARGS_IN_REGISTERS); 1655b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1656b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ faddp(1); break; 1657b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ fsubp(1); break; 1658b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ fmulp(1); break; 1659b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ fdivp(1); break; 1660b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1661b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1662b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label after_alloc_failure; 1663b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &after_alloc_failure); 1664b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1665b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1666b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&after_alloc_failure); 1667b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ffree(); 1668b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&call_runtime); 1669b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1670b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1671b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 1672b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 1673b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1674b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1675b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1676b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: { 1677b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // For MOD we go directly to runtime in the non-smi case. 1678b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1679b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1680b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1681b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1682b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1683b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1684b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1685b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: { 1686b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1687b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 1688b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label non_smi_result; 1689b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadUnknownsAsIntegers(masm, 1690b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch use_sse3_, 1691b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ¬_floats); 1692b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1693b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; 1694b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; 1695b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; 1696b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: __ sar_cl(eax); break; 1697b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: __ shl_cl(eax); break; 1698b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: __ shr_cl(eax); break; 1699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ == Token::SHR) { 1702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result is non-negative and fits in a smi. 1703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(eax, Immediate(0xc0000000)); 1704b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &call_runtime); 1705b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1706b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result fits in a smi. 1707b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(eax, 0xc0000000); 1708b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(negative, &non_smi_result); 1709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1710b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag smi result and return. 1711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(eax); 1712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1713b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // All ops except SHR return a signed int32 that we load in 1715b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // a HeapNumber. 1716b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ != Token::SHR) { 1717b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&non_smi_result); 1718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number if needed. 1719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, Operand(eax)); // ebx: result 1720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label skip_allocation; 1721b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode_) { 1722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: 1723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: 1724b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the operand was an object, we skip the 1725b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 1726b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 1727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1 * kPointerSize : 2 * kPointerSize)); 17283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 1729b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fall through! 1730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: 1731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 1732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 1733b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1734b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1735b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1736b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Store the result in the HeapNumber and return. 17378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1738b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1739b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm0, Operand(ebx)); 1740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ebx); 1743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fild_s(Operand(esp, 1 * kPointerSize)); 1744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 1750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransitionWithSavedArgs(masm); 1751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1752b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); break; 1754b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1756b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If an allocation fails, or SHR or MOD hit a hard case, 1757b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // use the runtime system to get the correct result. 1758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&call_runtime); 1759b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1760b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1761b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1762b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 1764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1765b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1766b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 1768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 1772b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1773b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1774b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1775b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 1776b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1777b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1778b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 1780b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1781b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 1783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1785b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 1786b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1787b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1788b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 1789b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1790b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1791b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 1792b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1793b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1794b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 1795b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1796b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1797b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 1798b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1799b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1800b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1801b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1802b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1803b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1804b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { 1806b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label call_runtime; 1807b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 180844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 180944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->generic_binary_stub_calls(), 1); 1810b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1811b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1812b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1813b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1814b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1815b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1816b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1817b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1818b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1819b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1820b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1821b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1822b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1823b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1824b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1825b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1826b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1827b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1828b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1829b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1830b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 1831b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1832b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Floating point case. 1833b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1834b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1835b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1836b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1837b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: { 1838b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 18398b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1840b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 1842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1843b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1844b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ addsd(xmm0, xmm1); break; 1845b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ subsd(xmm0, xmm1); break; 1846b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ mulsd(xmm0, xmm1); break; 1847b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ divsd(xmm0, xmm1); break; 1848b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &call_runtime); 1851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // SSE2 not available, use FPU. 1854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); 1855b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadFloatOperands( 1856b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch masm, 1857b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ecx, 1858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::ARGS_IN_REGISTERS); 1859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1860b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ faddp(1); break; 1861b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ fsubp(1); break; 1862b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ fmulp(1); break; 1863b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ fdivp(1); break; 1864b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1865b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1866b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label after_alloc_failure; 1867b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &after_alloc_failure); 1868b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1869b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1870b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&after_alloc_failure); 1871b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ffree(); 1872b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&call_runtime); 1873b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1874b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 1875b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1876b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1877b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: { 1878b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // For MOD we go directly to runtime in the non-smi case. 1879b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1880b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1881b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1882b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1883b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1884b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1885b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1886b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: { 1887b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label non_smi_result; 1888b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadUnknownsAsIntegers(masm, 1889b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch use_sse3_, 1890b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch &call_runtime); 1891b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1892b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; 1893b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; 1894b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; 1895b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: __ sar_cl(eax); break; 1896b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: __ shl_cl(eax); break; 1897b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: __ shr_cl(eax); break; 1898b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1899b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1900b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ == Token::SHR) { 1901b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result is non-negative and fits in a smi. 1902b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(eax, Immediate(0xc0000000)); 1903b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &call_runtime); 1904b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1905b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result fits in a smi. 1906b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(eax, 0xc0000000); 1907b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(negative, &non_smi_result); 1908b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1909b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag smi result and return. 1910b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(eax); 1911b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop the arguments from the stack. 1912b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1913b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // All ops except SHR return a signed int32 that we load in 1914b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // a HeapNumber. 1915b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ != Token::SHR) { 1916b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&non_smi_result); 1917b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number if needed. 1918b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, Operand(eax)); // ebx: result 1919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label skip_allocation; 1920b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode_) { 1921b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: 1922b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: 1923b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the operand was an object, we skip the 1924b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 1925b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 1926b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1 * kPointerSize : 2 * kPointerSize)); 19273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 1928b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fall through! 1929b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: 1930b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 1931b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 1932b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1933b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1934b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1935b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Store the result in the HeapNumber and return. 19368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1937b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1938b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm0, Operand(ebx)); 1939b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1940b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1941b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ebx); 1942b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fild_s(Operand(esp, 1 * kPointerSize)); 1943b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1944b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1945b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); 1946b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1947b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1948b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1949b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); break; 1950b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1951b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1952b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If all else fails, use the runtime system to get the correct 1953b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // result. 1954b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&call_runtime); 1955b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1956b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: { 19571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateAddStrings(masm); 1958b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1959b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 1960b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1961b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1962b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1963b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1964b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 1965b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1966b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1967b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1968b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 1969b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1970b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1971b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1972b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 1973b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1974b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1975b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 1976b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1977b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1978b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 1979b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1980b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1981b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 1982b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1983b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1984b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 1985b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1986b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1987b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 1988b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1989b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1990b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 1991b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1992b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1993b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 1994b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1995b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1996b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1997b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1998b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1999b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2000b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { 2002e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ASSERT(op_ == Token::ADD); 2003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label left_not_string, call_runtime; 20041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 20051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Registers containing left and right operands respectively. 20061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register left = edx; 20071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register right = eax; 20081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 20091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Test if left operand is a string. 20103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(left, &left_not_string, Label::kNear); 20111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); 2012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &left_not_string, Label::kNear); 20131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 20141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); 20151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateRegisterArgsPush(masm); 20161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ TailCallStub(&string_add_left_stub); 20171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 20181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Left operand is not a string, test right. 20191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&left_not_string); 20203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(right, &call_runtime, Label::kNear); 20211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); 2022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &call_runtime, Label::kNear); 20231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 20241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); 20251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateRegisterArgsPush(masm); 20261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ TailCallStub(&string_add_right_stub); 20271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 20281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Neither argument is a string. 20291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&call_runtime); 20301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 20311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 20321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapResultAllocation( 2034b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch MacroAssembler* masm, 2035b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* alloc_failure) { 2036b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label skip_allocation; 2037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch OverwriteMode mode = mode_; 2038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode) { 2039b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: { 2040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the argument in edx is already an object, we skip the 2041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 20423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(edx, &skip_allocation, Label::kNear); 2043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number for the result. Keep eax and edx intact 2044b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // for the possible runtime call. 2045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); 2046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Now edx can be overwritten losing one of the arguments as we are 2047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // now done and will not need it any more. 2048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, Operand(ebx)); 2049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 2050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Use object in edx as a result holder 2051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(edx)); 2052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2053b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: 2055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the argument in eax is already an object, we skip the 2056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 20573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 2058b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fall through! 2059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: 2060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number for the result. Keep eax and edx intact 2061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // for the possible runtime call. 2062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); 2063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Now eax can be overwritten losing one of the arguments as we are 2064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // now done and will not need it any more. 2065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, ebx); 2066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 2067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 2069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { 207480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ecx); 2075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(edx); 2076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(eax); 207780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ecx); 207880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 207980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 208080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 208180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::Generate(MacroAssembler* masm) { 2082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // TAGGED case: 2083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input: 2084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // esp[4]: tagged number input argument (should be number). 2085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // esp[0]: return address. 2086b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Output: 2087b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax: tagged double result. 2088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // UNTAGGED case: 2089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input:: 2090b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // esp[0]: return address. 2091b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // xmm1: untagged double input argument 2092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Output: 2093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // xmm1: untagged double result. 2094b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 209580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime_call; 209680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime_call_clear_stack; 2097b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label skip_cache; 2098b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const bool tagged = (argument_type_ == TAGGED); 2099b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Test that eax is a number. 2101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label input_not_smi; 2102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loaded; 2103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(esp, kPointerSize)); 21043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &input_not_smi, Label::kNear); 2105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input is a smi. Untag and load it onto the FPU stack. 2106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Then load the low and high words of the double into ebx, edx. 2107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTagSize == 1); 2108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sar(eax, 1); 2109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(Operand(esp), Immediate(2 * kPointerSize)); 2110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 0), eax); 2111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fild_s(Operand(esp, 0)); 2112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fst_d(Operand(esp, 0)); 2113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(edx); 2114b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(ebx); 2115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&loaded, Label::kNear); 2116b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&input_not_smi); 2117b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if input is a HeapNumber. 2118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 211944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 212044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(Operand(ebx), Immediate(factory->heap_number_map())); 2121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_equal, &runtime_call); 2122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input is a HeapNumber. Push it on the FPU stack and load its 2123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // low and high words into ebx, edx. 2124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); 2126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset)); 2127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&loaded); 2129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 21308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE4_1)) { 2131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope sse4_scope(SSE4_1); 2132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pextrd(Operand(edx), xmm1, 0x1); // copy xmm1[63..32] to edx. 2133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 2134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pshufd(xmm0, xmm1, 0x1); 2135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movd(Operand(edx), xmm0); 2136b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movd(Operand(ebx), xmm1); 2138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 213980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ST[0] or xmm1 == double value 214180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx = low 32 bits of double value 214280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx = high 32 bits of double value 214380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compute hash (the shifts are arithmetic): 214480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); 214580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, ebx); 214680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(ecx, Operand(edx)); 214780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, ecx); 214880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sar(eax, 16); 214980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(ecx, Operand(eax)); 215080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, ecx); 215180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sar(eax, 8); 215280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(ecx, Operand(eax)); 215344f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize)); 215444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ and_(Operand(ecx), 215544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(TranscendentalCache::SubCache::kCacheSize - 1)); 215680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2157b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ST[0] or xmm1 == double value. 215880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx = low 32 bits of double value. 215980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx = high 32 bits of double value. 216080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx = TranscendentalCache::hash(double value). 216144f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference cache_array = 216244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::transcendental_cache_array_address(masm->isolate()); 216344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, Immediate(cache_array)); 216444f0eee88ff00398ff7f715fab053374d808c90dSteve Block int cache_array_index = 216544f0eee88ff00398ff7f715fab053374d808c90dSteve Block type_ * sizeof(masm->isolate()->transcendental_cache()->caches_[0]); 216644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, Operand(eax, cache_array_index)); 216780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Eax points to the cache for the type type_. 216880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If NULL, the cache hasn't been initialized yet, so go through runtime. 216980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(eax, Operand(eax)); 217080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &runtime_call_clear_stack); 217180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG 217280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the layout of cache elements match expectations. 217344f0eee88ff00398ff7f715fab053374d808c90dSteve Block { TranscendentalCache::SubCache::Element test_elem[2]; 217480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_start = reinterpret_cast<char*>(&test_elem[0]); 217580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); 217680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); 217780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); 217880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); 217980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. 218080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(0, elem_in0 - elem_start); 218180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(kIntSize, elem_in1 - elem_start); 218280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(2 * kIntSize, elem_out - elem_start); 218380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 218480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 218580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find the address of the ecx'th entry in the cache, i.e., &eax[ecx*12]. 218680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(ecx, ecx, times_2, 0)); 218780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(eax, ecx, times_4, 0)); 218880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if cache matches: Double value is stored in uint32_t[2] array. 2189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label cache_miss; 219080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(ebx, Operand(ecx, 0)); 2191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &cache_miss, Label::kNear); 219280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, Operand(ecx, kIntSize)); 2193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &cache_miss, Label::kNear); 219480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Cache hit! 219580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(ecx, 2 * kIntSize)); 2196b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2197b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp(0); 2198b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(kPointerSize); 2199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 2200b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 2202b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 220380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 220480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&cache_miss); 220580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Update cache with new value. 220680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We are short on registers, so use no_reg as scratch. 220780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // This gives slightly larger code. 2208b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2209b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack); 2210b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 2211b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); 2212b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(Operand(esp), Immediate(kDoubleSize)); 2213b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(Operand(esp, 0), xmm1); 2214b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fld_d(Operand(esp, 0)); 2215b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(Operand(esp), Immediate(kDoubleSize)); 2216b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 221780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateOperation(masm); 221880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(ecx, 0), ebx); 221980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(ecx, kIntSize), edx); 222080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(ecx, 2 * kIntSize), eax); 222180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2222b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(kPointerSize); 2224b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 2225b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2226b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 2227b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2228b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Skip cache and return answer directly, only in untagged case. 2229b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_cache); 2230b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(Operand(esp), Immediate(kDoubleSize)); 2231b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(Operand(esp, 0), xmm1); 2232b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fld_d(Operand(esp, 0)); 2233b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateOperation(masm); 2234b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(Operand(esp, 0)); 2235b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, Operand(esp, 0)); 2236b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(Operand(esp), Immediate(kDoubleSize)); 2237b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // We return the value in xmm1 without adding it to the cache, but 2238b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // we cause a scavenging GC so that future allocations will succeed. 2239b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ EnterInternalFrame(); 2240b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate an unused object bigger than a HeapNumber. 2241b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(2 * kDoubleSize))); 2242b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); 2243b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ LeaveInternalFrame(); 2244b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 2245b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 224680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2247b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Call runtime, doing whatever allocation and cleanup is necessary. 2248b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2249b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&runtime_call_clear_stack); 2250b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp(0); 2251b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&runtime_call); 225244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference runtime = 225344f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference(RuntimeFunction(), masm->isolate()); 225444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ TailCallExternalReference(runtime, 1, 1); 2255b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 2256b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&runtime_call_clear_stack); 2257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&runtime_call); 2258b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); 2259b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm1); 2260b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ EnterInternalFrame(); 2261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(eax); 2262b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CallRuntime(RuntimeFunction(), 1); 2263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ LeaveInternalFrame(); 2264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2265b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 2266b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 226780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 226880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 226980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 227080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian MonsenRuntime::FunctionId TranscendentalCacheStub::RuntimeFunction() { 227180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen switch (type_) { 227280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case TranscendentalCache::SIN: return Runtime::kMath_sin; 227380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case TranscendentalCache::COS: return Runtime::kMath_cos; 2274b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case TranscendentalCache::LOG: return Runtime::kMath_log; 227580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen default: 227680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen UNIMPLEMENTED(); 227780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return Runtime::kAbort; 227880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 227980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 228080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 228180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 228280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) { 228380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Only free register is edi. 2284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input value is on FP stack, and also in ebx/edx. 2285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input value is possibly in xmm1. 2286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Address of result (a newly allocated HeapNumber) may be in eax. 2287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { 2288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Both fsin and fcos require arguments in the range +/-2^63 and 2289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // return NaN for infinities and NaN. They can share all code except 2290b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // the actual fsin/fcos operation. 2291257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label in_range, done; 2292b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If argument is outside the range -2^63..2^63, fsin/cos doesn't 2293b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // work. We must reduce it to the appropriate range. 2294b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edi, edx); 2295b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ and_(Operand(edi), Immediate(0x7ff00000)); // Exponent only. 2296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch int supported_exponent_limit = 2297b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift; 2298b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(Operand(edi), Immediate(supported_exponent_limit)); 2299257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, &in_range, Label::kNear); 2300b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for infinity and NaN. Both return NaN for sin. 2301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(Operand(edi), Immediate(0x7ff00000)); 2302257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_nan_result; 2303257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &non_nan_result, Label::kNear); 2304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input is +/-Infinity or NaN. Result is NaN. 2305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp(0); 2306b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // NaN is represented by 0x7ff8000000000000. 2307b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(0x7ff80000)); 2308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(0)); 2309b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fld_d(Operand(esp, 0)); 2310b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(Operand(esp), Immediate(2 * kPointerSize)); 2311257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 231280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2313257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_nan_result); 231480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Use fpmod to restrict argument to the range +/-2*PI. 2316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edi, eax); // Save eax before using fnstsw_ax. 2317257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fldpi(); 2318257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fadd(0); 2319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fld(1); 2320257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // FPU Stack: input, 2*pi, input. 2321257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch { 2322257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label no_exceptions; 2323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fwait(); 2324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fnstsw_ax(); 2325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Clear if Illegal Operand or Zero Division exceptions are set. 2326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(Operand(eax), Immediate(5)); 2327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &no_exceptions, Label::kNear); 2328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fnclex(); 2329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&no_exceptions); 2330257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 233180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute st(0) % st(1) 2333257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch { 2334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label partial_remainder_loop; 2335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&partial_remainder_loop); 2336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fprem1(); 2337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fwait(); 2338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fnstsw_ax(); 2339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(Operand(eax), Immediate(0x400 /* C2 */)); 2340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If C2 is set, computation only has partial result. Loop to 2341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // continue computation. 2342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &partial_remainder_loop); 2343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 2344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // FPU Stack: input, 2*pi, input % 2*pi 2345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fstp(2); 2346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fstp(0); 2347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(eax, edi); // Restore eax (allocated HeapNumber pointer). 234880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // FPU Stack: input % 2*pi 2350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&in_range); 2351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (type_) { 2352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case TranscendentalCache::SIN: 2353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fsin(); 2354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 2355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case TranscendentalCache::COS: 2356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fcos(); 2357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 2358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 2359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 236080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 2361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&done); 2362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 2363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(type_ == TranscendentalCache::LOG); 2364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fldln2(); 2365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fxch(); 2366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fyl2x(); 236780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 236880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 236980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 237080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 237180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Input: edx, eax are the left and right objects of a bit op. 237280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Output: eax, ecx are left and right integers for a bit op. 237380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm, 237480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool use_sse3, 237580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* conversion_failure) { 237680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check float operands. 237780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label arg1_is_object, check_undefined_arg1; 237880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label arg2_is_object, check_undefined_arg2; 237980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label load_arg2, done; 238080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 238180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Test if arg1 is a Smi. 23823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(edx, &arg1_is_object); 238380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 238480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edx); 238580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_arg2); 238680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 238780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the argument is undefined it converts to zero (ECMA-262, section 9.5). 238880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_undefined_arg1); 238944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 239044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(edx, factory->undefined_value()); 239180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, conversion_failure); 239280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Immediate(0)); 239380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_arg2); 239480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 239580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&arg1_is_object); 239680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 239744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(ebx, factory->heap_number_map()); 239880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &check_undefined_arg1); 239980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 240080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the untagged integer version of the edx heap number in ecx. 2401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch IntegerConvert(masm, edx, use_sse3, conversion_failure); 240280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, ecx); 240380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 240480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Here edx has the untagged integer, eax has a Smi or a heap number. 240580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_arg2); 240680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 240780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Test if arg2 is a Smi. 24083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &arg2_is_object); 240980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 241080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(eax); 241180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, eax); 241280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&done); 241380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 241480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the argument is undefined it converts to zero (ECMA-262, section 9.5). 241580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_undefined_arg2); 241644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, factory->undefined_value()); 241780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, conversion_failure); 241880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(0)); 241980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&done); 242080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 242180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&arg2_is_object); 242280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 242344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(ebx, factory->heap_number_map()); 242480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &check_undefined_arg2); 242580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 242680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the untagged integer version of the eax heap number in ecx. 2427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch IntegerConvert(masm, eax, use_sse3, conversion_failure); 242880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 242980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, edx); 243080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 243180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 243280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2433b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckLoadedIntegersWereInt32(MacroAssembler* masm, 2434b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch bool use_sse3, 2435b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* not_int32) { 2436b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return; 2437b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2438b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2439b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 244080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, 244180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register number) { 2442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_smi, done; 244380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 24443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(number, &load_smi, Label::kNear); 244580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); 2446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 244780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 244880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi); 244980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(number); 245080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(number); 245180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 245280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(number); 245380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 245480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 245580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 245680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 245780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 245880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm) { 2459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_smi_edx, load_eax, load_smi_eax, done; 246080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in edx into xmm0. 24613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); 246280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 246380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 246480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_eax); 246580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in eax into xmm1. 24663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); 246780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 246980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 247080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_edx); 247180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edx); // Untag smi before converting to float. 247280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtsi2sd(xmm0, Operand(edx)); 247380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(edx); // Retag smi for heap number overwriting test. 247480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_eax); 247580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 247680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_eax); 247780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(eax); // Untag smi before converting to float. 247880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtsi2sd(xmm1, Operand(eax)); 247980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(eax); // Retag smi for heap number overwriting test. 248080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 248180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 248280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 248380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 248480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 248580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm, 248680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_numbers) { 2487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; 248880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in edx into xmm0, or branch to not_numbers. 24893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); 249044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 249144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map()); 249280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_numbers); // Argument in edx is not a number. 249380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 249480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_eax); 249580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in eax into xmm1, or branch to not_numbers. 24963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); 249744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map()); 2498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &load_float_eax, Label::kNear); 249980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(not_numbers); // Argument in eax is not a number. 250080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_edx); 250180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edx); // Untag smi before converting to float. 250280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtsi2sd(xmm0, Operand(edx)); 250380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(edx); // Retag smi for heap number overwriting test. 250480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_eax); 250580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_eax); 250680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(eax); // Untag smi before converting to float. 250780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtsi2sd(xmm1, Operand(eax)); 250880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(eax); // Retag smi for heap number overwriting test. 2509257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 251080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_float_eax); 251180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 251280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 251380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 251480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 251580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 251680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Smis(MacroAssembler* masm, 251780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 251880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const Register left = edx; 251980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const Register right = eax; 252080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, left); 252180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(right)); // We're about to clobber scratch. 252280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 252380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtsi2sd(xmm0, Operand(scratch)); 252480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 252580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, right); 252680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 252780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtsi2sd(xmm1, Operand(scratch)); 252880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 252980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 253080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm, 2532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* non_int32, 2533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register scratch) { 2534b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvttsd2si(scratch, Operand(xmm0)); 2535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm2, Operand(scratch)); 2536b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm0, xmm2); 2537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, non_int32); 2538b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(carry, non_int32); 2539b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvttsd2si(scratch, Operand(xmm1)); 2540b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm2, Operand(scratch)); 2541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm1, xmm2); 2542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, non_int32); 2543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(carry, non_int32); 2544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 254780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, 254880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch, 254980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ArgLocation arg_location) { 2550257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_smi_1, load_smi_2, done_load_1, done; 255180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (arg_location == ARGS_IN_REGISTERS) { 255280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, edx); 255380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 255480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, Operand(esp, 2 * kPointerSize)); 255580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 25563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(scratch, &load_smi_1, Label::kNear); 255780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); 255880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done_load_1); 255980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 256080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (arg_location == ARGS_IN_REGISTERS) { 256180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, eax); 256280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 256380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, Operand(esp, 1 * kPointerSize)); 256480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 25653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(scratch, &load_smi_2, Label::kNear); 256680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); 2567257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 256880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 256980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_1); 257080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 257180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(scratch); 257280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 257380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(scratch); 257480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&done_load_1); 257580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 257680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_2); 257780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 257880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(scratch); 257980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 258080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(scratch); 258180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 258280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 258380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 258480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 258580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 258680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatSmis(MacroAssembler* masm, 258780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 258880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const Register left = edx; 258980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const Register right = eax; 259080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, left); 259180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(right)); // We're about to clobber scratch. 259280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 259380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(scratch); 259480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 259580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 259680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, right); 259780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 259880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 0), scratch); 259980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 260080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(scratch); 260180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 260280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 260380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 260480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, 260580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* non_float, 260680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 2607257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label test_other, done; 260880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Test if both operands are floats or smi -> scratch=k_is_float; 260980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Otherwise scratch = k_not_float. 26103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(edx, &test_other, Label::kNear); 261180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset)); 261244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 261344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(scratch, factory->heap_number_map()); 261480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, non_float); // argument in edx is not a number -> NaN 261580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 261680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&test_other); 26173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &done, Label::kNear); 261880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset)); 261944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(scratch, factory->heap_number_map()); 262080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, non_float); // argument in eax is not a number -> NaN 262180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 262280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fall-through: Both operands are numbers. 262380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 262480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 262580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 262680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2627b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm, 2628b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* non_int32) { 2629b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return; 2630b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2632b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2633b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid MathPowStub::Generate(MacroAssembler* masm) { 2634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Registers are used as follows: 2635b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // edx = base 2636b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax = exponent 2637b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ecx = temporary, result 2638b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2639b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 2640b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label allocate_return, call_runtime; 2641b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2642b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Load input parameters. 2643b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, Operand(esp, 2 * kPointerSize)); 2644b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(esp, 1 * kPointerSize)); 2645b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2646b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Save 1 in xmm3 - we need this several times later on. 2647b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Immediate(1)); 2648b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm3, Operand(ecx)); 2649b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2650b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label exponent_nonsmi; 2651b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label base_nonsmi; 2652b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the exponent is a heap number go to that specific case. 26533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &exponent_nonsmi); 26543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(edx, &base_nonsmi); 2655b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2656e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Optimized version when both exponent and base are smis. 2657b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label powi; 2658b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(edx); 2659b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm0, Operand(edx)); 2660b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&powi); 2661b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // exponent is smi and base is a heapnumber. 2662b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&base_nonsmi); 266344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 2664b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(FieldOperand(edx, HeapObject::kMapOffset), 266544f0eee88ff00398ff7f715fab053374d808c90dSteve Block factory->heap_number_map()); 2666b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_equal, &call_runtime); 2667b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2668b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 2669b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2670b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Optimized version of pow if exponent is a smi. 2671b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // xmm0 contains the base. 2672b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&powi); 2673b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(eax); 2674b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2675b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Save exponent in base as we need to check if exponent is negative later. 2676b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // We know that base and exponent are in different registers. 2677b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, eax); 2678b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2679b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Get absolute value of exponent. 2680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label no_neg; 2681b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(eax, 0); 2682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(greater_equal, &no_neg, Label::kNear); 2683b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ neg(eax); 2684b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&no_neg); 2685b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2686b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Load xmm1 with 1. 2687b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movsd(xmm1, xmm3); 2688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label while_true; 2689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label no_multiply; 2690b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2691b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&while_true); 2692b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ shr(eax, 1); 2693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_carry, &no_multiply, Label::kNear); 2694b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mulsd(xmm1, xmm0); 2695b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&no_multiply); 2696b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mulsd(xmm0, xmm0); 2697b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &while_true); 2698b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // base has the original value of the exponent - if the exponent is 2700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // negative return 1/result. 2701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(edx, Operand(edx)); 2702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(positive, &allocate_return); 2703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Special case if xmm1 has reached infinity. 2704b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Immediate(0x7FB00000)); 2705b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movd(xmm0, Operand(ecx)); 2706b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtss2sd(xmm0, xmm0); 2707b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm0, xmm1); 2708b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(equal, &call_runtime); 2709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ divsd(xmm3, xmm1); 2710b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movsd(xmm1, xmm3); 2711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&allocate_return); 2712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2713b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // exponent (or both) is a heapnumber - no matter what we should now work 2714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // on doubles. 2715b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&exponent_nonsmi); 2716b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(FieldOperand(eax, HeapObject::kMapOffset), 271744f0eee88ff00398ff7f715fab053374d808c90dSteve Block factory->heap_number_map()); 2718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_equal, &call_runtime); 2719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2720b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Test if exponent is nan. 2721b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm1, xmm1); 2722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(parity_even, &call_runtime); 2723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label base_not_smi; 2725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label handle_special_cases; 27263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(edx, &base_not_smi, Label::kNear); 2727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(edx); 2728b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm0, Operand(edx)); 2729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&handle_special_cases, Label::kNear); 2730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&base_not_smi); 2732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(FieldOperand(edx, HeapObject::kMapOffset), 273344f0eee88ff00398ff7f715fab053374d808c90dSteve Block factory->heap_number_map()); 2734b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_equal, &call_runtime); 2735b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); 2736b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ and_(ecx, HeapNumber::kExponentMask); 2737b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(Operand(ecx), Immediate(HeapNumber::kExponentMask)); 2738b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // base is NaN or +/-Infinity 2739b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(greater_equal, &call_runtime); 2740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 2741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // base is in xmm0 and exponent is in xmm1. 2743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&handle_special_cases); 2744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_minus_half; 2745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Test for -0.5. 2746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Load xmm2 with -0.5. 2747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Immediate(0xBF000000)); 2748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movd(xmm2, Operand(ecx)); 2749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtss2sd(xmm2, xmm2); 2750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // xmm2 now has -0.5. 2751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm2, xmm1); 2752257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, ¬_minus_half, Label::kNear); 2753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2754b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Calculates reciprocal of square root. 27551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // sqrtsd returns -0 when input is -0. ECMA spec requires +0. 2756257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xorps(xmm1, xmm1); 27571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ addsd(xmm1, xmm0); 2758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sqrtsd(xmm1, xmm1); 27591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ divsd(xmm3, xmm1); 27601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movsd(xmm1, xmm3); 2761b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&allocate_return); 2762b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Test for 0.5. 2764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_minus_half); 2765b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Load xmm2 with 0.5. 2766b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3. 2767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ addsd(xmm2, xmm3); 2768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // xmm2 now has 0.5. 2769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm2, xmm1); 2770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_equal, &call_runtime); 2771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Calculates square root. 27721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // sqrtsd returns -0 when input is -0. ECMA spec requires +0. 2773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xorps(xmm1, xmm1); 27741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ addsd(xmm1, xmm0); 2775b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sqrtsd(xmm1, xmm1); 2776b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2777b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&allocate_return); 2778b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(ecx, eax, edx, &call_runtime); 2779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm1); 2780b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, ecx); 2781e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ret(2 * kPointerSize); 2782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&call_runtime); 2784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); 2785b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2786b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2787b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 278880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { 278980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The key is in edx and the parameter count is in eax. 279080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 279180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The displacement is used for skipping the frame pointer on the 279280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stack. It is the offset of the last parameter (if any) relative 279380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // to the frame pointer. 279480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kDisplacement = 1 * kPointerSize; 279580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 279680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the key is a smi. 279780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow; 27983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(edx, &slow); 279980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 280080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the calling frame is an arguments adaptor frame. 2801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label adaptor; 280280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 280380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset)); 280480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 2805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &adaptor, Label::kNear); 280680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 280780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check index against formal parameters count limit passed in 280880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // through register eax. Use unsigned comparison to get negative 280980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // check for free. 281080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, Operand(eax)); 2811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &slow); 281280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 281380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the argument from the stack and return it. 281480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize == 1); 281580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these. 281680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ebx, Operand(ebp, eax, times_2, 0)); 281780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ neg(edx); 281880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); 281980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 282080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 282180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Arguments adaptor case: Check index against actual arguments 282280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // limit found in the arguments adaptor frame. Use unsigned 282380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // comparison to get negative check for free. 282480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&adaptor); 282580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 282680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, Operand(ecx)); 2827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &slow); 282880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 282980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the argument from the stack and return it. 283080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize == 1); 283180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these. 283280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ebx, Operand(ebx, ecx, times_2, 0)); 283380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ neg(edx); 283480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); 283580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 283680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 283780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case: Handle non-smi or out-of-bounds access to arguments 283880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // by calling the runtime system. 283980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 284080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ebx); // Return address. 284180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(edx); 284280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ebx); 284380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); 284480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 284580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 284680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 28473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { 284880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[0] : return address 284980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[4] : number of parameters 285080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[8] : receiver displacement 28513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] : function 28523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 28533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Check if the calling frame is an arguments adaptor frame. 28543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label runtime; 28553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 28563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 28573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 28583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(not_equal, &runtime, Label::kNear); 28593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 28603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Patch the arguments.length and the parameters pointer. 28613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 28623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ecx); 28633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edx, Operand(edx, ecx, times_2, 28643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch StandardFrameConstants::kCallerSPOffset)); 28653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(Operand(esp, 2 * kPointerSize), edx); 28663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 28673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&runtime); 28683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); 28693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch} 28703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 28713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 28723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { 28733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] : return address 28743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] : number of parameters (tagged) 28753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] : receiver displacement 28763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] : function 28773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 28783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = parameter count (tagged) 28793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, Operand(esp, 1 * kPointerSize)); 28803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 28813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Check if the calling frame is an arguments adaptor frame. 28823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // TODO(rossberg): Factor out some of the bits that are shared with the other 28833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Generate* functions. 28843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label runtime; 28853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label adaptor_frame, try_allocate; 28863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 28873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 28883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 28893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(equal, &adaptor_frame, Label::kNear); 28903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 28913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // No adaptor, parameter count = argument count. 28923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, ebx); 28933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(&try_allocate, Label::kNear); 28943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 28953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We have an adaptor frame. Patch the parameters pointer. 28963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&adaptor_frame); 28973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 28983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edx, Operand(edx, ecx, times_2, 28993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch StandardFrameConstants::kCallerSPOffset)); 29003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(Operand(esp, 2 * kPointerSize), edx); 29013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = parameter count (tagged) 29033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 29043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] = parameter count (tagged) 29053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = address of receiver argument 29063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Compute the mapped parameter count = min(ebx, ecx) in ebx. 29073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(ebx, Operand(ecx)); 29083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(less_equal, &try_allocate, Label::kNear); 29093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, ecx); 29103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&try_allocate); 29123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Save mapped parameter count. 29143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(ebx); 29153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Compute the sizes of backing store, parameter map, and arguments object. 29173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 1. Parameter map, has 2 extra words containing context and backing store. 29183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int kParameterMapHeaderSize = 29193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch FixedArray::kHeaderSize + 2 * kPointerSize; 29203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label no_parameter_map; 29213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ test(ebx, Operand(ebx)); 29223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(zero, &no_parameter_map, Label::kNear); 29233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize)); 29243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&no_parameter_map); 29253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 2. Backing store. 29273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); 29283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 3. Arguments object. 29303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(Operand(ebx), Immediate(Heap::kArgumentsObjectSize)); 29313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Do the allocation of all three objects in one go. 29333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT); 29343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // eax = address of new object(s) (tagged) 29363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 29373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = mapped parameter count (tagged) 29383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = parameter count (tagged) 29393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] = address of receiver argument 29403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Get the arguments boilerplate from the current (global) context into edi. 29413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label has_mapped_parameters, copy; 29423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 29433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); 29443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, Operand(esp, 0 * kPointerSize)); 29453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ test(ebx, Operand(ebx)); 29463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(not_zero, &has_mapped_parameters, Label::kNear); 29473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, Operand(edi, 29483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX))); 29493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(©, Label::kNear); 29503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&has_mapped_parameters); 29523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, Operand(edi, 29533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX))); 29543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(©); 29553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // eax = address of new object (tagged) 29573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = mapped parameter count (tagged) 29583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 29593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edi = address of boilerplate object (tagged) 29603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = mapped parameter count (tagged) 29613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = parameter count (tagged) 29623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] = address of receiver argument 29633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy the JS object part. 29643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { 29653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, FieldOperand(edi, i)); 29663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(eax, i), edx); 29673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch } 29683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Setup the callee in-object property. 29703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); 29713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, Operand(esp, 4 * kPointerSize)); 29723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(eax, JSObject::kHeaderSize + 29733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsCalleeIndex * kPointerSize), 29743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch edx); 29753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Use the length (smi tagged) and set that as an in-object property too. 29773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); 29783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(eax, JSObject::kHeaderSize + 29793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsLengthIndex * kPointerSize), 29803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch ecx); 29813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Setup the elements pointer in the allocated arguments object. 29833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // If we allocated a parameter map, edi will point there, otherwise to the 29843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // backing store. 29853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edi, Operand(eax, Heap::kArgumentsObjectSize)); 29863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); 29873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // eax = address of new object (tagged) 29893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = mapped parameter count (tagged) 29903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 29913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edi = address of parameter map or backing store (tagged) 29923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = mapped parameter count (tagged) 29933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = parameter count (tagged) 29943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] = address of receiver argument 29953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Free a register. 29963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(eax); 29973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Initialize parameter map. If there are no mapped arguments, we're done. 29993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label skip_parameter_map; 30003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ test(ebx, Operand(ebx)); 30013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(zero, &skip_parameter_map); 300280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 30033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kMapOffset), 30043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Immediate(FACTORY->non_strict_arguments_elements_map())); 30053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2)))); 30063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax); 30073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi); 30083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize)); 30093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax); 30103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy the parameter slots and the holes in the arguments. 30123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We need to fill in mapped_parameter_count slots. They index the context, 30133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // where parameters are stored in reverse order, at 30143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 30153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // The mapped parameter thus need to get indices 30163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS+parameter_count-1 .. 30173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count 30183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We loop from right to left. 30193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label parameters_loop, parameters_test; 30203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(ecx); 30213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(eax, Operand(esp, 2 * kPointerSize)); 30223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); 30233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(ebx, Operand(esp, 4 * kPointerSize)); 30243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(ebx, Operand(eax)); 30253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, FACTORY->the_hole_value()); 30263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, edi); 30273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize)); 30283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // eax = loop variable (tagged) 30293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = mapping index (tagged) 30303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = the hole value 30313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edx = address of parameter map (tagged) 30323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edi = address of backing store (tagged) 30333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = argument count (tagged) 30343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] = address of new object (tagged) 30353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = mapped parameter count (tagged) 30363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[16] = parameter count (tagged) 30373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[20] = address of receiver argument 30383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(¶meters_test, Label::kNear); 30393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(¶meters_loop); 30413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(Operand(eax), Immediate(Smi::FromInt(1))); 30423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx); 30433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx); 30443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(Operand(ebx), Immediate(Smi::FromInt(1))); 30453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(¶meters_test); 30463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ test(eax, Operand(eax)); 30473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(not_zero, ¶meters_loop, Label::kNear); 30483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ pop(ecx); 30493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&skip_parameter_map); 30513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 30533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edi = address of backing store (tagged) 30543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = address of new object (tagged) 30553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] = mapped parameter count (tagged) 30563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] = parameter count (tagged) 30573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[16] = address of receiver argument 30583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy arguments header and remaining slots (if there are any). 30593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kMapOffset), 30603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Immediate(FACTORY->fixed_array_map())); 30613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); 30623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label arguments_loop, arguments_test; 30643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, Operand(esp, 1 * kPointerSize)); 30653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, Operand(esp, 4 * kPointerSize)); 30663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(Operand(edx), ebx); // Is there a smarter way to do negative scaling? 30673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(Operand(edx), ebx); 30683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(&arguments_test, Label::kNear); 30693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&arguments_loop); 30713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(Operand(edx), Immediate(kPointerSize)); 30723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(eax, Operand(edx, 0)); 30733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax); 30743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(Operand(ebx), Immediate(Smi::FromInt(1))); 30753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&arguments_test); 30773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(ebx, Operand(ecx)); 30783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(less, &arguments_loop, Label::kNear); 30793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Restore. 30813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ pop(eax); // Address of arguments object. 30823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ pop(ebx); // Parameter count. 30833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Return and remove the on-stack parameters. 30853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ret(3 * kPointerSize); 30863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Do the runtime call to allocate the arguments object. 30883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&runtime); 30893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ pop(eax); // Remove saved parameter count. 30903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ecx); // Patch argument count. 30913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); 30923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch} 30933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { 30963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] : return address 30973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] : number of parameters 30983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] : receiver displacement 30993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] : function 310080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 310180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the calling frame is an arguments adaptor frame. 310280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label adaptor_frame, try_allocate, runtime; 310380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 310480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 310580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 310680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &adaptor_frame); 310780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 310880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the length from the frame. 310980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esp, 1 * kPointerSize)); 311080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&try_allocate); 311180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 311280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Patch the arguments.length and the parameters pointer. 311380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&adaptor_frame); 311480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 311580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 1 * kPointerSize), ecx); 31163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edx, Operand(edx, ecx, times_2, 31173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch StandardFrameConstants::kCallerSPOffset)); 311880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 2 * kPointerSize), edx); 311980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 312080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try the new space allocation. Start out with computing the size of 312180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the arguments object and the elements array. 3122257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label add_arguments_object; 312380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&try_allocate); 312480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Operand(ecx)); 3125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &add_arguments_object, Label::kNear); 312680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize)); 312780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&add_arguments_object); 31283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(Operand(ecx), Immediate(Heap::kArgumentsObjectSizeStrict)); 312980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 313080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the allocation of both objects in one go. 313180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT); 313280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 313380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the arguments boilerplate from the current (global) context. 313480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 313580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); 31363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int offset = 31373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX); 31383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, Operand(edi, offset)); 313980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 314080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy the JS object part. 314180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { 314280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(edi, i)); 314380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, i), ebx); 314480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 314580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 314680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the length (smi tagged) and set that as an in-object property too. 314744f0eee88ff00398ff7f715fab053374d808c90dSteve Block STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); 314880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esp, 1 * kPointerSize)); 314944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(FieldOperand(eax, JSObject::kHeaderSize + 31503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsLengthIndex * kPointerSize), 315144f0eee88ff00398ff7f715fab053374d808c90dSteve Block ecx); 315280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 315380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If there are no actual arguments, we're done. 315480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label done; 315580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Operand(ecx)); 315680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &done); 315780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 315880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the parameters pointer from the stack. 315980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 2 * kPointerSize)); 316080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 316180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Setup the elements pointer in the allocated arguments object and 316280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // initialize the header in the elements fixed array. 31633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict)); 316480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); 316580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(edi, FixedArray::kMapOffset), 31663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Immediate(FACTORY->fixed_array_map())); 316744f0eee88ff00398ff7f715fab053374d808c90dSteve Block 316880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); 316980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Untag the length for the loop below. 317080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ecx); 317180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 317280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy the fixed array slots. 3173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop; 317480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 317580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(edx, -1 * kPointerSize)); // Skip receiver. 317680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx); 317780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edi), Immediate(kPointerSize)); 317880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(edx), Immediate(kPointerSize)); 317980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ dec(ecx); 318080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &loop); 318180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 318280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameters. 318380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 318480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 318580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 318680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the runtime call to allocate the arguments object. 318780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 31883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); 318980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 319080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 319180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 319280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid RegExpExecStub::Generate(MacroAssembler* masm) { 319380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump directly to runtime if native RegExp is not selected at compile 319480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // time or if regexp entry in generated code is turned off runtime switch or 319580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // at compilation. 319680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef V8_INTERPRETED_REGEXP 319780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 319880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else // V8_INTERPRETED_REGEXP 319980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!FLAG_regexp_entry_native) { 320080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 320180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return; 320280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 320380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 320480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 320580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[0]: return address 320680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[4]: last_match_info (expected JSArray) 320780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[8]: previous index 320880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[12]: subject string 320980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[16]: JSRegExp object 321080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 321180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kLastMatchInfoOffset = 1 * kPointerSize; 321280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kPreviousIndexOffset = 2 * kPointerSize; 321380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kSubjectOffset = 3 * kPointerSize; 321480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kJSRegExpOffset = 4 * kPointerSize; 321580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 321680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime, invoke_regexp; 321780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 321880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Ensure that a RegExp stack is allocated. 321980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference address_of_regexp_stack_memory_address = 322044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_regexp_stack_memory_address( 322144f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 322280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference address_of_regexp_stack_memory_size = 322344f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_regexp_stack_memory_size(masm->isolate()); 322480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); 322580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ebx, Operand(ebx)); 3226257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &runtime); 322780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 322880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the first argument is a JSRegExp object. 322980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kJSRegExpOffset)); 323080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 32313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &runtime); 323280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); 323380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 323480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the RegExp has been compiled (data contains a fixed array). 323580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); 323680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 323780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Immediate(kSmiTagMask)); 323880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected"); 323980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); 324080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); 324180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 324280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 324380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 324480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. 324580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset)); 324680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand(ebx), Immediate(Smi::FromInt(JSRegExp::IRREGEXP))); 324780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 324880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 324980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 325080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the number of captures fit in the static offsets vector buffer. 325180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); 325280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate number of capture registers (number_of_captures + 1) * 2. This 325380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // uses the asumption that smis are 2 * their untagged value. 325480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 325580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 325680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), Immediate(2)); // edx was a smi. 325780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the static offsets vector buffer is large enough. 325880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize); 325980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above, &runtime); 326080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 326180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 326280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: Number of capture registers 326380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the second argument is a string. 326480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kSubjectOffset)); 32653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &runtime); 326680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); 326780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(NegateCondition(is_string), &runtime); 326880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the length of the string to ebx. 326980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); 327080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 327180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: Length of subject string as a smi 327280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 327380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: Number of capture registers 327480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the third argument is a positive smi less than the subject 327580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // string length. A negative value will be greater (unsigned comparison). 327680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kPreviousIndexOffset)); 32773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &runtime); 327880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, Operand(ebx)); 327980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &runtime); 328080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 328180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 328280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: Number of capture registers 328380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the fourth object is a JSArray object. 328480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kLastMatchInfoOffset)); 32853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &runtime); 328680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); 328780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 328880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the JSArray is in fast case. 328980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); 329080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset)); 329144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 329244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, factory->fixed_array_map()); 329380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 329480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the last match info has space for the capture registers and the 329580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // additional information. 329680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset)); 329780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(eax); 329880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), Immediate(RegExpImpl::kLastMatchOverhead)); 329980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, Operand(eax)); 330080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(greater, &runtime); 330180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 330280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 330380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the representation and encoding of the subject string. 330480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label seq_ascii_string, seq_two_byte_string, check_code; 330580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kSubjectOffset)); 330680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 330780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 330880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // First check for flat two byte string. 330980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(ebx, 331080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask); 331180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); 331280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &seq_two_byte_string); 331380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Any other flat string must be a flat ascii string. 331480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(Operand(ebx), 331580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(kIsNotStringMask | kStringRepresentationMask)); 331680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &seq_ascii_string); 331780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 331880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for flat cons string. 331980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // A flat cons string is a cons string where the second part is the empty 332080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // string. In that case the subject string is just the first part of the cons 332180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // string. Also in this case the first part of the cons string is known to be 332280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // a sequential string or an external string. 332380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kExternalStringTag != 0); 332480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0); 332580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(Operand(ebx), 332680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(kIsNotStringMask | kExternalStringTag)); 332780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &runtime); 332880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // String is a cons string. 332980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(eax, ConsString::kSecondOffset)); 333044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(Operand(edx), factory->empty_string()); 333180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 333280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); 333380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 333480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // String is a cons string with empty second part. 333580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first part of cons string. 333680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: map of first part of cons string. 333780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Is first part a flat two byte string? 333880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), 333980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen kStringRepresentationMask | kStringEncodingMask); 334080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); 334180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &seq_two_byte_string); 334280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Any other flat string must be ascii. 334380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), 334480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen kStringRepresentationMask); 334580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &runtime); 334680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 334780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&seq_ascii_string); 334880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: subject string (flat ascii) 334980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 335080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset)); 335180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(edi, Immediate(1)); // Type is ascii. 335280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&check_code); 335380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 335480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&seq_two_byte_string); 335580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: subject string (flat two byte) 335680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 335780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset)); 335880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(edi, Immediate(0)); // Type is two byte. 335980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 336080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_code); 336180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the irregexp code has been generated for the actual string 336280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // encoding. If it has, the field contains a code object otherwise it contains 3363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // a smi (code flushing support). 3364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfSmi(edx, &runtime); 336580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 336680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: subject string 336780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: code 336880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: encoding of subject string (1 if ascii, 0 if two_byte); 336980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load used arguments before starting to push arguments for call to native 337080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // RegExp code to avoid handling changing stack height. 337180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(esp, kPreviousIndexOffset)); 337280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ebx); // Previous index from smi. 337380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 337480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: subject string 337580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: previous index 337680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: code 337780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: encoding of subject string (1 if ascii 0 if two_byte); 337880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // All checks done. Now push arguments for native regexp code. 337944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 338044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->regexp_entry_native(), 1); 338180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 338244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Isolates: note we add an additional parameter here (isolate pointer). 338344f0eee88ff00398ff7f715fab053374d808c90dSteve Block static const int kRegExpExecuteArguments = 8; 3384e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ EnterApiExitFrame(kRegExpExecuteArguments); 338580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 338644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Argument 8: Pass current isolate address. 338744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(Operand(esp, 7 * kPointerSize), 338844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(ExternalReference::isolate_address())); 338944f0eee88ff00398ff7f715fab053374d808c90dSteve Block 339080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 7: Indicate that this is a direct call from JavaScript. 339180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 6 * kPointerSize), Immediate(1)); 339280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 339380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 6: Start (high end) of backtracking stack memory area. 339480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_address)); 339580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); 339680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 5 * kPointerSize), ecx); 339780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 339880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 5: static offsets vector buffer. 339980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 4 * kPointerSize), 340044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(ExternalReference::address_of_static_offsets_vector( 340144f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()))); 340280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 340380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 4: End of string data 340480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 3: Start of string data 3405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label setup_two_byte, setup_rest; 340680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(edi, Operand(edi)); 340780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(eax, String::kLengthOffset)); 3408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &setup_two_byte, Label::kNear); 340980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edi); 341080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, FieldOperand(eax, edi, times_1, SeqAsciiString::kHeaderSize)); 341180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. 341280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); 341380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. 3414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&setup_rest, Label::kNear); 341580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 341680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&setup_two_byte); 341780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 341880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize == 1); // edi is smi (powered by 2). 341980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, FieldOperand(eax, edi, times_1, SeqTwoByteString::kHeaderSize)); 342080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. 342180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); 342280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. 342380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 342480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&setup_rest); 342580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 342680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 2: Previous index. 342780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 1 * kPointerSize), ebx); 342880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 342980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 1: Subject string. 343080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 0 * kPointerSize), eax); 343180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 343280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate the code entry and call it. 343380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag)); 3434e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ call(Operand(edx)); 3435e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3436e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Drop arguments and come back to JS mode. 3437e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LeaveApiExitFrame(); 343880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 343980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the result. 344080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label success; 344180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS); 3442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &success); 344380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label failure; 344480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); 3445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &failure); 344680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); 344780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If not exception it can only be retry. Handle that in the runtime system. 344880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 344980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result must now be exception. If there is no pending exception already a 345080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stack overflow (on the backtrack stack) was detected in RegExp code but 345180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // haven't created the exception yet. Handle that in the runtime system. 345280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // TODO(592): Rerunning the RegExp to get the stack overflow exception. 345344f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference pending_exception(Isolate::k_pending_exception_address, 345444f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 3455e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(edx, 345644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Operand::StaticVariable(ExternalReference::the_hole_value_location( 345744f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()))); 3458e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(eax, Operand::StaticVariable(pending_exception)); 3459e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cmp(edx, Operand(eax)); 346080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &runtime); 3461e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // For exception, throw the exception again. 3462e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3463e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Clear the pending exception variable. 3464e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(Operand::StaticVariable(pending_exception), edx); 3465e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3466e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Special handling of termination exceptions which are uncatchable 3467e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // by javascript code. 346844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, factory->termination_exception()); 3469e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label throw_termination_exception; 3470e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ j(equal, &throw_termination_exception); 3471e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3472e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Handle normal exception by following handler chain. 3473e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Throw(eax); 3474e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3475e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&throw_termination_exception); 3476e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ThrowUncatchable(TERMINATION, eax); 3477e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 347880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&failure); 3479e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // For failure to match, return null. 348044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(Operand(eax), factory->null_value()); 348180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(4 * kPointerSize); 348280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 348380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load RegExp data. 348480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&success); 348580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kJSRegExpOffset)); 348680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); 348780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); 348880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate number of capture registers (number_of_captures + 1) * 2. 348980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 349080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 349180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), Immediate(2)); // edx was a smi. 349280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 349380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: Number of capture registers 349480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load last_match_info which is still known to be a fast case JSArray. 349580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kLastMatchInfoOffset)); 349680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); 349780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 349880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: last_match_info backing store (FixedArray) 349980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: number of capture registers 350080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store the capture count. 350180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(edx); // Number of capture registers to smi. 350280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ebx, RegExpImpl::kLastCaptureCountOffset), edx); 350380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edx); // Number of capture registers back from smi. 350480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store last subject and last input. 350580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kSubjectOffset)); 350680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax); 350780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, ebx); 350880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ RecordWrite(ecx, RegExpImpl::kLastSubjectOffset, eax, edi); 350980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kSubjectOffset)); 351080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax); 351180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, ebx); 351280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ RecordWrite(ecx, RegExpImpl::kLastInputOffset, eax, edi); 351380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 351480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the static offsets vector filled by the native regexp code. 351580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference address_of_static_offsets_vector = 351644f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_static_offsets_vector(masm->isolate()); 351780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(address_of_static_offsets_vector)); 351880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 351980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: last_match_info backing store (FixedArray) 352080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: offsets vector 352180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: number of capture registers 3522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label next_capture, done; 352380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Capture register counter starts from number of capture registers and 352480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // counts down until wraping after zero. 352580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&next_capture); 352680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(edx), Immediate(1)); 3527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(negative, &done, Label::kNear); 352880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the value from the static offsets vector buffer. 352980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, Operand(ecx, edx, times_int_size, 0)); 353080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(edi); 353180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store the smi value in the last match info. 353280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ebx, 353380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen edx, 353480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_pointer_size, 353580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen RegExpImpl::kFirstCaptureOffset), 353680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen edi); 353780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&next_capture); 353880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 353980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 354080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return last match info. 354180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kLastMatchInfoOffset)); 354280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(4 * kPointerSize); 354380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 354480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the runtime call to execute the regexp. 354580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 354680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 354780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif // V8_INTERPRETED_REGEXP 354880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 354980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 355080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid RegExpConstructResultStub::Generate(MacroAssembler* masm) { 3552b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const int kMaxInlineLength = 100; 3553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label slowcase; 3554257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done; 3555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, Operand(esp, kPointerSize * 3)); 35563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(ebx, &slowcase); 3557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(Operand(ebx), Immediate(Smi::FromInt(kMaxInlineLength))); 3558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(above, &slowcase); 3559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Smi-tagging is equivalent to multiplying by 2. 3560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 3561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTagSize == 1); 3562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate RegExpResult followed by FixedArray with size in ebx. 3563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // JSArray: [Map][empty properties][Elements][Length-smi][index][input] 3564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Elements: [Map][Length][..elements..] 3565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize, 3566b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch times_half_pointer_size, 3567b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ebx, // In: Number of elements (times 2, being a smi) 3568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch eax, // Out: Start of allocation (tagged). 3569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ecx, // Out: End of allocation. 3570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch edx, // Scratch register 3571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch &slowcase, 3572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch TAG_OBJECT); 3573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax: Start of allocated area, object-tagged. 3574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3575b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set JSArray map to global.regexp_result_map(). 3576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set empty properties FixedArray. 3577b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set elements to point to FixedArray allocated right after the JSArray. 3578b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Interleave operations for better latency. 3579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX)); 358044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 358144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(ecx, Immediate(factory->empty_fixed_array())); 3582b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ lea(ebx, Operand(eax, JSRegExpResult::kSize)); 3583b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset)); 3584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx); 3585b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx); 3586b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX)); 3587b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, HeapObject::kMapOffset), edx); 3588b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3589b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set input, index and length fields from arguments. 3590b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(esp, kPointerSize * 1)); 3591b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSRegExpResult::kInputOffset), ecx); 3592b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(esp, kPointerSize * 2)); 3593b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSRegExpResult::kIndexOffset), ecx); 3594b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(esp, kPointerSize * 3)); 3595b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSArray::kLengthOffset), ecx); 3596b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3597b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill out the elements FixedArray. 3598b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax: JSArray. 3599b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ebx: FixedArray. 3600b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ecx: Number of elements in array, as smi. 3601b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3602b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set map. 3603b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(ebx, HeapObject::kMapOffset), 360444f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(factory->fixed_array_map())); 3605b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set length. 3606b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(ebx, FixedArray::kLengthOffset), ecx); 3607b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill contents of fixed-array with the-hole. 3608b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(ecx); 360944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(edx, Immediate(factory->the_hole_value())); 3610b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize)); 3611b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill fixed array elements with hole. 3612b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax: JSArray. 3613b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ecx: Number of elements to fill. 3614b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ebx: Start of elements in FixedArray. 3615b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // edx: the hole. 3616b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label loop; 3617b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(ecx, Operand(ecx)); 3618b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&loop); 3619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(less_equal, &done, Label::kNear); // Jump if ecx is negative or zero. 3620b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(Operand(ecx), Immediate(1)); 3621b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(ebx, ecx, times_pointer_size, 0), edx); 3622b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&loop); 3623b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3624b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&done); 3625b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(3 * kPointerSize); 3626b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3627b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&slowcase); 3628b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); 3629b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 3630b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 363280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, 363380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register object, 363480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register result, 363580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 363680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 363780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool object_is_smi, 363880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_found) { 363980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Use of registers. Register result is used as a temporary. 364080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register number_string_cache = result; 364180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register mask = scratch1; 364280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch = scratch2; 364380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 364480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the number string cache. 364544f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference roots_address = 364644f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::roots_address(masm->isolate()); 364780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex)); 364880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(number_string_cache, 364980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Operand::StaticArray(scratch, times_pointer_size, roots_address)); 365080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make the hash mask from the length of the number string cache. It 365180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // contains two elements (number and string) for each cache entry. 365280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset)); 365380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shr(mask, kSmiTagSize + 1); // Untag length and divide it by two. 365480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(mask), Immediate(1)); // Make mask. 365580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 365680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate the entry in the number string cache. The hash value in the 365780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // number string cache for smis is just the smi value, and the hash for 365880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // doubles is the xor of the upper and lower words. See 365980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Heap::GetNumberStringCache. 3660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label smi_hash_calculated; 3661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_result_from_cache; 366280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (object_is_smi) { 366380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, object); 366480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 366580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 3666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_smi; 366780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 36683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(object, ¬_smi, Label::kNear); 366980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, object); 367080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 3671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&smi_hash_calculated, Label::kNear); 367280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_smi); 367380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(object, HeapObject::kMapOffset), 367444f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()->factory()->heap_number_map()); 367580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_found); 367680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(8 == kDoubleSize); 367780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset)); 367880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); 367980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Object is heap number and hash is now in scratch. Calculate cache index. 368080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(scratch, Operand(mask)); 368180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register index = scratch; 368280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register probe = mask; 368380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(probe, 368480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(number_string_cache, 368580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index, 368680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_twice_pointer_size, 368780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize)); 36883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(probe, not_found); 36898b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 369080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope fscope(SSE2); 369180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset)); 369280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset)); 369380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ucomisd(xmm0, xmm1); 369480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 369580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(object, HeapNumber::kValueOffset)); 369680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset)); 369780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ FCmp(); 369880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 369980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(parity_even, not_found); // Bail out if NaN is involved. 370080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_found); // The cache did not contain this value. 3701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&load_result_from_cache, Label::kNear); 370280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 370380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 370480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&smi_hash_calculated); 370580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Object is smi and hash is now in scratch. Calculate cache index. 370680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(scratch, Operand(mask)); 370780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register index = scratch; 370880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the entry is the smi we are looking for. 370980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(object, 371080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(number_string_cache, 371180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index, 371280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_twice_pointer_size, 371380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize)); 371480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_found); 371580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 371680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the result from the cache. 371780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_result_from_cache); 371880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result, 371980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(number_string_cache, 372080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index, 372180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_twice_pointer_size, 372280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize + kPointerSize)); 372344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 372444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->number_to_string_native(), 1); 372580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 372680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 372780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 372880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::Generate(MacroAssembler* masm) { 372980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 373080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 373180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(esp, kPointerSize)); 373280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 373380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Generate code to lookup number in the number string cache. 373480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateLookupNumberStringCache(masm, ebx, eax, ecx, edx, false, &runtime); 373580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(1 * kPointerSize); 373680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 373780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 373880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle number to string in the runtime system if not found in the cache. 373980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1); 374080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 374180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 374280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 374380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic int NegativeComparisonResult(Condition cc) { 374480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(cc != equal); 374580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT((cc == less) || (cc == less_equal) 374680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen || (cc == greater) || (cc == greater_equal)); 374780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return (cc == greater || cc == greater_equal) ? LESS : GREATER; 374880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 374980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 375080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::Generate(MacroAssembler* masm) { 375180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 375280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 375380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label check_unequal_objects, done; 375480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 37550d5e116f6aee03185f237311a943491bb079a768Kristian Monsen // Compare two smis if required. 37560d5e116f6aee03185f237311a943491bb079a768Kristian Monsen if (include_smi_compare_) { 37570d5e116f6aee03185f237311a943491bb079a768Kristian Monsen Label non_smi, smi_done; 37580d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ mov(ecx, Operand(edx)); 37590d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ or_(ecx, Operand(eax)); 37603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(ecx, &non_smi); 37610d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ sub(edx, Operand(eax)); // Return on the result of the subtraction. 37620d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ j(no_overflow, &smi_done); 3763f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch __ not_(edx); // Correct sign in case of overflow. edx is never 0 here. 37640d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ bind(&smi_done); 37650d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ mov(eax, edx); 37660d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ ret(0); 37670d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ bind(&non_smi); 37680d5e116f6aee03185f237311a943491bb079a768Kristian Monsen } else if (FLAG_debug_code) { 37690d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ mov(ecx, Operand(edx)); 37700d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ or_(ecx, Operand(eax)); 37710d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ test(ecx, Immediate(kSmiTagMask)); 37720d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ Assert(not_zero, "Unexpected smi operands."); 37730d5e116f6aee03185f237311a943491bb079a768Kristian Monsen } 37740d5e116f6aee03185f237311a943491bb079a768Kristian Monsen 377580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NOTICE! This code is only reached after a smi-fast-case check, so 377680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // it is certain that at least one operand isn't a smi. 377780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 377880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Identical objects can be compared fast, but there are some tricky cases 377980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // for NaN and undefined. 378080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen { 378180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label not_identical; 378280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, Operand(edx)); 378380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, ¬_identical); 378480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 378580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ != equal) { 378680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for undefined. undefined OP undefined is false even though 378780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // undefined == undefined. 3788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label check_for_nan; 378944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(edx, masm->isolate()->factory()->undefined_value()); 3790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &check_for_nan, Label::kNear); 379180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); 379280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 379380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_for_nan); 379480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 379580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 379644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Test for NaN. Sadly, we can't just compare to factory->nan_value(), 379780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // so we do the second best thing - test it ourselves. 379880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Note: if cc_ != equal, never_nan_nan_ is not used. 379980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (never_nan_nan_ && (cc_ == equal)) { 380080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 380180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 380280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 3803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label heap_number; 380480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(edx, HeapObject::kMapOffset), 380544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(masm->isolate()->factory()->heap_number_map())); 3806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &heap_number, Label::kNear); 380780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ != equal) { 380880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call runtime on identical JSObjects. Otherwise return equal. 38093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); 381080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, ¬_identical); 381180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 381280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 381380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 381480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 381580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&heap_number); 381680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // It is a heap number, so return non-equal if it's NaN and equal if 381780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // it's not NaN. 381880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The representation of NaN values has all exponent bits (52..62) set, 381980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and not all mantissa bits (0..51) clear. 382080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We only accept QNaNs, which have bit 51 set. 382180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read top bits of double representation (second word of value). 382280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 382380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., 382480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // all bits in the mask are set. We only need to check the word 382580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // that contains the exponent and high bit of the mantissa. 382680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0); 382780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); 38289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Set(eax, Immediate(0)); 382980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Shift value and mask so kQuietNaNHighBitsMask applies to topmost 383080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // bits. 383180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(edx, Operand(edx)); 383280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, kQuietNaNHighBitsMask << 1); 383380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal) { 383480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(EQUAL != 1); 383580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ setcc(above_equal, eax); 383680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 383780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 3838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label nan; 3839257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &nan, Label::kNear); 384080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 384180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 384280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&nan); 384380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); 384480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 384580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 384680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 384780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 384880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_identical); 384980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 385080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 385180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Strict equality can quickly decide whether objects are equal. 385280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Non-strict object equality is slower, so it is handled later in the stub. 385380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal && strict_) { 385480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow; // Fallthrough label. 3855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_smis; 385680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If we're doing a strict equality comparison, we don't have to do 385780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // type conversion, so we generate code to do fast comparison for objects 385880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and oddballs. Non-smi numbers and strings still go through the usual 385980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // slow-case code. 386080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If either is a Smi (we know that not both are), then they can only 386180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // be equal if the other is a HeapNumber. If so, use the slow case. 386280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 386380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT_EQ(0, Smi::FromInt(0)); 386480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(kSmiTagMask)); 386580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(ecx, Operand(eax)); 386680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Operand(edx)); 3867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, ¬_smis, Label::kNear); 386880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // One operand is a smi. 386980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 387080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check whether the non-smi is a heap number. 387180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagMask == 1); 387280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx still holds eax & kSmiTag, which is either zero or one. 387380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(ecx), Immediate(0x01)); 387480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, edx); 387580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(ebx, Operand(eax)); 387680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(ebx, Operand(ecx)); // ebx holds either 0 or eax ^ edx. 387780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(ebx, Operand(eax)); 387880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // if eax was smi, ebx is now edx, else eax. 387980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 388080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the non-smi operand is a heap number. 388180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), 388244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(masm->isolate()->factory()->heap_number_map())); 388380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If heap number, handle it in the slow case. 388480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &slow); 388580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return non-equal (ebx is not zero) 388680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, ebx); 388780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 388880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 388980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_smis); 389080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If either operand is a JSObject or an oddball value, then they are not 389180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // equal since their pointers are different 389280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // There is no test for undetectability in strict equality. 389380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 389480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the type of the first operand. 389580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the first object is a JS object, we have done pointer comparison. 3896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label first_non_object; 38973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); 38983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); 3899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, &first_non_object, Label::kNear); 390080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 390180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return non-zero (eax is not zero) 3902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label return_not_equal; 390380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kHeapObjectTag != 0); 390480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&return_not_equal); 390580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 390680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 390780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&first_non_object); 390880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for oddballs: true, false, null, undefined. 390980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpInstanceType(ecx, ODDBALL_TYPE); 391080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &return_not_equal); 391180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 39123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ecx); 391380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &return_not_equal); 391480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 391580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for oddballs: true, false, null, undefined. 391680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpInstanceType(ecx, ODDBALL_TYPE); 391780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &return_not_equal); 391880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 391980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fall through to the general case. 392080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 392180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 392280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 392380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Generate the number comparison code. 392480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (include_number_compare_) { 392580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_number_comparison; 392680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label unordered; 39278b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 392880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope use_sse2(SSE2); 392980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope use_cmov(CMOV); 393080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 393180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); 393280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ucomisd(xmm0, xmm1); 393380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 393480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Don't base result on EFLAGS when a NaN is involved. 3935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(parity_even, &unordered); 393680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return a result of -1, 0, or 1, based on EFLAGS. 393780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, 0); // equal 393880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(Smi::FromInt(1))); 393980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmov(above, eax, Operand(ecx)); 394080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(Smi::FromInt(-1))); 394180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmov(below, eax, Operand(ecx)); 394280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 394380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 394480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FloatingPointHelper::CheckFloatOperands( 394580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen masm, &non_number_comparison, ebx); 394680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FloatingPointHelper::LoadFloatOperand(masm, eax); 394780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FloatingPointHelper::LoadFloatOperand(masm, edx); 394880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ FCmp(); 394980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 395080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Don't base result on EFLAGS when a NaN is involved. 3951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(parity_even, &unordered); 395280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label below_label, above_label; 395480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return a result of -1, 0, or 1, based on EFLAGS. 3955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, &below_label); 3956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above, &above_label); 395780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 39589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Set(eax, Immediate(0)); 395980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 396080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 396180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&below_label); 396280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(Smi::FromInt(-1))); 396380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 396480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 396580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&above_label); 396680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(Smi::FromInt(1))); 396780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 396880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 396980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 397080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If one of the numbers was NaN, then the result is always false. 397180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The cc is never not-equal. 397280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&unordered); 397380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(cc_ != not_equal); 397480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == less || cc_ == less_equal) { 397580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(Smi::FromInt(1))); 397680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 397780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(Smi::FromInt(-1))); 397880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 397980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 398080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 398180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The number comparison code did not provide a valid result. 398280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_number_comparison); 398380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 398480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 398580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fast negative check for symbol-to-symbol equality. 398680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label check_for_strings; 398780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal) { 398880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); 398980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); 399080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 399180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We've already checked for object identity, so if both operands 399280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // are symbols they aren't equal. Register eax already holds a 399380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // non-zero value, which indicates not equal, so just return. 399480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 399580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 399680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 399780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_for_strings); 399880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 399980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, 400080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &check_unequal_objects); 400180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 400280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Inline comparison of ascii strings. 4003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (cc_ == equal) { 4004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringCompareStub::GenerateFlatAsciiStringEquals(masm, 400580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen edx, 400680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen eax, 400780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ecx, 4008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ebx); 4009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 4010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringCompareStub::GenerateCompareFlatAsciiStrings(masm, 4011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch edx, 4012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch eax, 4013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ecx, 4014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ebx, 4015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch edi); 4016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 401780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG 401880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fall-through from string comparison"); 401980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 402080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 402180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_unequal_objects); 402280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal && !strict_) { 402380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Non-strict equality. Objects are unequal if 402480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // they are both JSObjects and not undetectable, 402580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and their pointers are different. 4026257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_both_objects; 4027257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label return_unequal; 402880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // At most one is a smi, so we can test for smi by adding the two. 402980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // A smi plus a heap object has the low bit set, a heap object plus 403080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // a heap object has the low bit clear. 403180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 403280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagMask == 1); 403380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(eax, edx, times_1, 0)); 403480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Immediate(kSmiTagMask)); 4035257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, ¬_both_objects, Label::kNear); 40363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); 4037257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, ¬_both_objects, Label::kNear); 40383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx); 4039257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, ¬_both_objects, Label::kNear); 404080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We do not bail out after this point. Both are JSObjects, and 404180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // they are equal if and only if both are undetectable. 404280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The and of the undetectable flags is 1 if and only if they are equal. 404380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 404480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1 << Map::kIsUndetectable); 4045257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &return_unequal, Label::kNear); 404680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ebx, Map::kBitFieldOffset), 404780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1 << Map::kIsUndetectable); 4048257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &return_unequal, Label::kNear); 404980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The objects are both undetectable, so they both compare as the value 405080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // undefined, and are equal. 405180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(EQUAL)); 405280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&return_unequal); 405380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return non-equal by returning the non-zero object pointer in eax, 405480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // or return equal if we fell through to here. 405580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); // rax, rdx were pushed 405680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_both_objects); 405780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 405880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 405980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Push arguments below the return address. 406080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ecx); 406180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(edx); 406280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(eax); 406380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 406480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Figure out which native to call and setup the arguments. 406580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Builtins::JavaScript builtin; 406680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal) { 406780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; 406880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 406980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen builtin = Builtins::COMPARE; 407080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); 407180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 407280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 407380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore return address on the stack. 407480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ecx); 407580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 407680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) 407780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // tagged as a small integer. 407880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ InvokeBuiltin(builtin, JUMP_FUNCTION); 407980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 408080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 408180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 408280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::BranchIfNonSymbol(MacroAssembler* masm, 408380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* label, 408480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register object, 408580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 40863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(object, label); 408780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset)); 408880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); 408980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(scratch, kIsSymbolMask | kIsNotStringMask); 409080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(scratch, kSymbolTag | kStringTag); 409180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, label); 409280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 409380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 409480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 409580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StackCheckStub::Generate(MacroAssembler* masm) { 4096f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch __ TailCallRuntime(Runtime::kStackGuard, 0, 1); 409780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 409880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 409980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 410080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CallFunctionStub::Generate(MacroAssembler* masm) { 410180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow; 410280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // The receiver might implicitly be the global object. This is 4104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // indicated by passing the hole as the receiver to the call 4105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // function stub. 4106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (ReceiverMightBeImplicit()) { 4107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label call; 410880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the receiver from the stack. 410980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // +1 ~ return address 411080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, (argc_ + 1) * kPointerSize)); 4111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Call as function is indicated with the hole. 4112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(eax, masm->isolate()->factory()->the_hole_value()); 4113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &call, Label::kNear); 4114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Patch the receiver on the stack with the global receiver object. 4115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ebx, GlobalObjectOperand()); 4116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); 4117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(Operand(esp, (argc_ + 1) * kPointerSize), ebx); 4118257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call); 411980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 412080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 412180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the function to call from the stack. 412280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // +2 ~ receiver, return address 412380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, Operand(esp, (argc_ + 2) * kPointerSize)); 412480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 412580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the function really is a JavaScript function. 41263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(edi, &slow); 412780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Goto slow case if we do not have a function. 412880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 4129257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &slow); 413080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 413180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fast-case: Just invoke the function. 413280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ParameterCount actual(argc_); 4133257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 4134257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (ReceiverMightBeImplicit()) { 4135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label call_as_function; 4136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(eax, masm->isolate()->factory()->the_hole_value()); 4137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &call_as_function); 4138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeFunction(edi, 4139257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch actual, 4140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch JUMP_FUNCTION, 4141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch NullCallWrapper(), 4142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CALL_AS_METHOD); 4143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_as_function); 4144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 4145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeFunction(edi, 4146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch actual, 4147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch JUMP_FUNCTION, 4148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch NullCallWrapper(), 4149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CALL_AS_FUNCTION); 415080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 415180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case: Non-function called. 415280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 415380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // CALL_NON_FUNCTION expects the non-function callee as receiver (instead 415480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // of the original receiver from the call site). 415580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi); 415680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(argc_)); 415780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(ebx, Immediate(0)); 415880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); 415944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Handle<Code> adaptor = 416044f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); 41613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SetCallKind(ecx, CALL_AS_METHOD); 416280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(adaptor, RelocInfo::CODE_TARGET); 416380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 416480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 416580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 416644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool CEntryStub::NeedsImmovableCode() { 416744f0eee88ff00398ff7f715fab053374d808c90dSteve Block return false; 416844f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 416944f0eee88ff00398ff7f715fab053374d808c90dSteve Block 417044f0eee88ff00398ff7f715fab053374d808c90dSteve Block 417180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { 4172e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Throw(eax); 417380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 417480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 417580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 417680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateCore(MacroAssembler* masm, 417780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_normal_exception, 417880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_termination_exception, 417980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_out_of_memory_exception, 418080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool do_gc, 41811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block bool always_allocate_scope) { 418280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result parameter for PerformGC, if any 418380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: pointer to C function (C callee-saved) 418480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebp: frame pointer (restored after C call) 418580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp: stack pointer (restored after C call) 418680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: number of arguments including receiver (C callee-saved) 418780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: pointer to the first argument (C callee-saved) 418880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 418980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result returned in eax, or eax+edx if result_size_ is 2. 419080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 419180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check stack alignment. 419280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 419380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CheckStackAlignment(); 419480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 419580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 419680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (do_gc) { 419780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Pass failure code returned from last attempt as first argument to 419880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the 419980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stack alignment is known to be correct. This function takes one argument 420080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // which is passed on the stack, and we know that the stack has been 420180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // prepared to pass at least one argument. 420280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 0 * kPointerSize), eax); // Result. 420380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY); 420480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 420580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 420680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference scope_depth = 420744f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::heap_always_allocate_scope_depth(masm->isolate()); 420880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (always_allocate_scope) { 420980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ inc(Operand::StaticVariable(scope_depth)); 421080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 421180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 421280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call C function. 421380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 0 * kPointerSize), edi); // argc. 421480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 1 * kPointerSize), esi); // argv. 421544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(Operand(esp, 2 * kPointerSize), 421644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(ExternalReference::isolate_address())); 421780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ call(Operand(ebx)); 421880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is in eax or edx:eax - do not destroy these registers! 421980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 422080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (always_allocate_scope) { 422180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ dec(Operand::StaticVariable(scope_depth)); 422280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 422380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 422480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure we're not trying to return 'the hole' from the runtime 422580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // call as this may lead to crashes in the IC code later. 422680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 4227257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label okay; 422844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, masm->isolate()->factory()->the_hole_value()); 4229257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &okay, Label::kNear); 423080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ int3(); 423180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&okay); 423280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 423380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 423480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for failure result. 423580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label failure_returned; 423680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); 423780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(eax, 1)); 423880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Lower 2 bits of ecx are 0 iff eax has failure tag. 423980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Immediate(kFailureTagMask)); 4240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &failure_returned); 424180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 424244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference pending_exception_address( 424344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate::k_pending_exception_address, masm->isolate()); 42441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 42451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check that there is no pending exception, otherwise we 42461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // should have returned some failure value. 42471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (FLAG_debug_code) { 42481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(edx); 42491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(edx, Operand::StaticVariable( 425044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::the_hole_value_location(masm->isolate()))); 4251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label okay; 42521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ cmp(edx, Operand::StaticVariable(pending_exception_address)); 42531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Cannot use check here as it attempts to generate call into runtime. 4254257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &okay, Label::kNear); 42551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ int3(); 42561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&okay); 42571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ pop(edx); 42581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 42591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 426080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Exit the JavaScript to C++ exit frame. 4261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ LeaveExitFrame(save_doubles_); 426280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 426380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 426480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handling of failure. 426580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&failure_returned); 426680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 426780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label retry; 426880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the returned exception is RETRY_AFTER_GC continue at retry label 426980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); 427080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); 4271257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &retry); 427280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 427380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Special handling of out of memory exceptions. 427480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException())); 427580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, throw_out_of_memory_exception); 427680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 427780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Retrieve the pending exception and clear the variable. 427844f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference the_hole_location = 427944f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::the_hole_value_location(masm->isolate()); 428080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand::StaticVariable(pending_exception_address)); 428144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(edx, Operand::StaticVariable(the_hole_location)); 428280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(pending_exception_address), edx); 428380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 428480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Special handling of termination exceptions which are uncatchable 428580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // by javascript code. 428644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, masm->isolate()->factory()->termination_exception()); 428780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, throw_termination_exception); 428880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 428980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle normal exception. 429080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(throw_normal_exception); 429180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 429280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Retry. 429380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&retry); 429480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 429580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 429680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 429780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, 429880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen UncatchableExceptionType type) { 4299e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ThrowUncatchable(type, eax); 430080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 430180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 430280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 430380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::Generate(MacroAssembler* masm) { 430480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: number of arguments including receiver 430580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: pointer to C function (C callee-saved) 430680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebp: frame pointer (restored after C call) 430780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp: stack pointer (restored after C call) 430880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: current context (C callee-saved) 430980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: JS function of the caller (C callee-saved) 431080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 431180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NOTE: Invocations of builtins may return failure objects instead 431280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // of a proper result. The builtin entry handles this by performing 431380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // a garbage collection and retrying the builtin (twice). 431480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 431580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Enter the exit frame that transitions from JavaScript to C++. 4316b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ EnterExitFrame(save_doubles_); 431780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 431880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result parameter for PerformGC, if any (setup below) 431980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: pointer to builtin function (C callee-saved) 432080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebp: frame pointer (restored after C call) 432180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp: stack pointer (restored after C call) 432280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: number of arguments including receiver (C callee-saved) 432380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: argv pointer (C callee-saved) 432480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 432580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_normal_exception; 432680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_termination_exception; 432780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_out_of_memory_exception; 432880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 432980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call into the runtime system. 433080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 433180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 433280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 433380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 433480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen false, 433580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen false); 433680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 433780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do space-specific GC and retry runtime call. 433880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 433980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 434080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 434180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 434280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen true, 434380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen false); 434480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 434580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do full GC and retry runtime call one final time. 434680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Failure* failure = Failure::InternalError(); 434780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure))); 434880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 434980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 435080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 435180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 435280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen true, 435380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen true); 435480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 435580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_out_of_memory_exception); 435680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateThrowUncatchable(masm, OUT_OF_MEMORY); 435780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 435880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_termination_exception); 435980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateThrowUncatchable(masm, TERMINATION); 436080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 436180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_normal_exception); 436280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateThrowTOS(masm); 436380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 436480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 436580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 436680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { 436780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label invoke, exit; 436880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label not_outermost_js, not_outermost_js_2; 436980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 437080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Setup frame. 437180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ebp); 437280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebp, Operand(esp)); 437380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 437480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Push marker in two places. 437580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; 437680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Immediate(Smi::FromInt(marker))); // context slot 437780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Immediate(Smi::FromInt(marker))); // function slot 437880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Save callee-saved registers (C calling conventions). 437980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(edi); 438080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(esi); 438180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ebx); 438280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 438380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Save copies of the top frame descriptor on the stack. 438444f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference c_entry_fp(Isolate::k_c_entry_fp_address, masm->isolate()); 438580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Operand::StaticVariable(c_entry_fp)); 438680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 438780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If this is the outermost JS call, set js_entry_sp value. 438844f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, 438944f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 439080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0)); 439180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, ¬_outermost_js); 439280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(js_entry_sp), ebp); 4393053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); 4394053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block Label cont; 4395053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ jmp(&cont); 439680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_outermost_js); 4397053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME))); 4398053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ bind(&cont); 439980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 440080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call a faked try-block that does the invoke. 440180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ call(&invoke); 440280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 440380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Caught exception: Store result (exception) in the pending 440480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // exception field in the JSEnv and return a failure sentinel. 440544f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference pending_exception(Isolate::k_pending_exception_address, 440644f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 440780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(pending_exception), eax); 440880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception())); 440980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&exit); 441080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 441180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Invoke: Link this frame into the handler chain. 441280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&invoke); 441380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); 441480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 441580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Clear any pending exceptions. 441644f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference the_hole_location = 441744f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::the_hole_value_location(masm->isolate()); 441844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(edx, Operand::StaticVariable(the_hole_location)); 441980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(pending_exception), edx); 442080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 442180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fake a receiver (NULL). 442280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Immediate(0)); // receiver 442380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 442480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Invoke the function by calling through JS entry trampoline 442580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // builtin and pop the faked function when we return. Notice that we 442680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // cannot store a reference to the trampoline code directly in this 442780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stub, because the builtin stubs may not have been generated yet. 442880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (is_construct) { 442944f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference construct_entry( 443044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Builtins::kJSConstructEntryTrampoline, 443144f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 443280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Immediate(construct_entry)); 443380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 443444f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference entry(Builtins::kJSEntryTrampoline, 443544f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 443680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Immediate(entry)); 443780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 443880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(edx, 0)); // deref address 443980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); 444080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ call(Operand(edx)); 444180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 444280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Unlink this frame from the handler chain. 4443053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ PopTryHandler(); 444480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4445053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ bind(&exit); 4446053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block // Check if the current stack frame is marked as the outermost JS frame. 4447053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ pop(ebx); 4448053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ cmp(Operand(ebx), 4449053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); 445080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, ¬_outermost_js_2); 445180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0)); 445280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_outermost_js_2); 445380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 445480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore the top frame descriptor from the stack. 445544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ pop(Operand::StaticVariable(ExternalReference( 445644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate::k_c_entry_fp_address, 445744f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()))); 445880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 445980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore callee-saved registers (C calling conventions). 446080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ebx); 446180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(esi); 446280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(edi); 446380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(esp), Immediate(2 * kPointerSize)); // remove markers 446480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 446580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore frame pointer and return. 446680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ebp); 446780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 446880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 446980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 447080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4471086aeeaae12517475c22695a200be45495516549Ben Murdoch// Generate stub code for instanceof. 4472086aeeaae12517475c22695a200be45495516549Ben Murdoch// This code can patch a call site inlined cache of the instance of check, 4473086aeeaae12517475c22695a200be45495516549Ben Murdoch// which looks like this. 4474086aeeaae12517475c22695a200be45495516549Ben Murdoch// 4475086aeeaae12517475c22695a200be45495516549Ben Murdoch// 81 ff XX XX XX XX cmp edi, <the hole, patched to a map> 4476086aeeaae12517475c22695a200be45495516549Ben Murdoch// 75 0a jne <some near label> 4477086aeeaae12517475c22695a200be45495516549Ben Murdoch// b8 XX XX XX XX mov eax, <the hole, patched to either true or false> 4478086aeeaae12517475c22695a200be45495516549Ben Murdoch// 4479086aeeaae12517475c22695a200be45495516549Ben Murdoch// If call site patching is requested the stack will have the delta from the 4480086aeeaae12517475c22695a200be45495516549Ben Murdoch// return address to the cmp instruction just below the return address. This 4481086aeeaae12517475c22695a200be45495516549Ben Murdoch// also means that call site patching can only take place with arguments in 4482086aeeaae12517475c22695a200be45495516549Ben Murdoch// registers. TOS looks like this when call site patching is requested 4483086aeeaae12517475c22695a200be45495516549Ben Murdoch// 4484086aeeaae12517475c22695a200be45495516549Ben Murdoch// esp[0] : return address 4485086aeeaae12517475c22695a200be45495516549Ben Murdoch// esp[4] : delta from return address to cmp instruction 4486086aeeaae12517475c22695a200be45495516549Ben Murdoch// 448780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid InstanceofStub::Generate(MacroAssembler* masm) { 4488086aeeaae12517475c22695a200be45495516549Ben Murdoch // Call site inlining and patching implies arguments in registers. 4489086aeeaae12517475c22695a200be45495516549Ben Murdoch ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck()); 4490086aeeaae12517475c22695a200be45495516549Ben Murdoch 4491b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fixed register usage throughout the stub. 4492b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register object = eax; // Object (lhs). 4493b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register map = ebx; // Map of the object. 4494b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register function = edx; // Function (rhs). 4495b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register prototype = edi; // Prototype of the function. 4496b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register scratch = ecx; 4497b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4498086aeeaae12517475c22695a200be45495516549Ben Murdoch // Constants describing the call site code to patch. 4499086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int kDeltaToCmpImmediate = 2; 4500086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int kDeltaToMov = 8; 4501086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int kDeltaToMovImmediate = 9; 4502086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int8_t kCmpEdiImmediateByte1 = BitCast<int8_t, uint8_t>(0x81); 4503086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int8_t kCmpEdiImmediateByte2 = BitCast<int8_t, uint8_t>(0xff); 4504086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8); 4505086aeeaae12517475c22695a200be45495516549Ben Murdoch 450644f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference roots_address = 450744f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::roots_address(masm->isolate()); 4508086aeeaae12517475c22695a200be45495516549Ben Murdoch 4509086aeeaae12517475c22695a200be45495516549Ben Murdoch ASSERT_EQ(object.code(), InstanceofStub::left().code()); 4510086aeeaae12517475c22695a200be45495516549Ben Murdoch ASSERT_EQ(function.code(), InstanceofStub::right().code()); 4511086aeeaae12517475c22695a200be45495516549Ben Murdoch 4512b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Get the object and function - they are always both needed. 4513b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label slow, not_js_object; 4514086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasArgsInRegisters()) { 4515b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(object, Operand(esp, 2 * kPointerSize)); 4516b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(function, Operand(esp, 1 * kPointerSize)); 4517b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 451880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 451980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the left hand is a JS object. 45203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(object, ¬_js_object); 4521b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); 452280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4523086aeeaae12517475c22695a200be45495516549Ben Murdoch // If there is a call site cache don't look in the global cache, but do the 4524086aeeaae12517475c22695a200be45495516549Ben Murdoch // real lookup and update the call site cache. 4525086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasCallSiteInlineCheck()) { 4526086aeeaae12517475c22695a200be45495516549Ben Murdoch // Look up the function and the map in the instanceof cache. 4527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 4528086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); 4529086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmp(function, 4530086aeeaae12517475c22695a200be45495516549Ben Murdoch Operand::StaticArray(scratch, times_pointer_size, roots_address)); 4531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 4532086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); 4533086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmp(map, Operand::StaticArray( 4534086aeeaae12517475c22695a200be45495516549Ben Murdoch scratch, times_pointer_size, roots_address)); 4535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 4536086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); 4537086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(eax, Operand::StaticArray( 4538086aeeaae12517475c22695a200be45495516549Ben Murdoch scratch, times_pointer_size, roots_address)); 4539086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 4540086aeeaae12517475c22695a200be45495516549Ben Murdoch __ bind(&miss); 4541086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4542086aeeaae12517475c22695a200be45495516549Ben Murdoch 4543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Get the prototype of the function. 4544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TryGetFunctionPrototype(function, prototype, scratch, &slow); 454580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 454680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the function prototype is a JS object. 45473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(prototype, &slow); 4548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); 4549b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4550086aeeaae12517475c22695a200be45495516549Ben Murdoch // Update the global instanceof or call site inlined cache with the current 4551086aeeaae12517475c22695a200be45495516549Ben Murdoch // map and function. The cached answer will be set when it is known below. 4552086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasCallSiteInlineCheck()) { 4553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); 4554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), map); 4555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); 4556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), 4557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch function); 4558086aeeaae12517475c22695a200be45495516549Ben Murdoch } else { 4559086aeeaae12517475c22695a200be45495516549Ben Murdoch // The constants for the code patching are based on no push instructions 4560086aeeaae12517475c22695a200be45495516549Ben Murdoch // at the call site. 4561086aeeaae12517475c22695a200be45495516549Ben Murdoch ASSERT(HasArgsInRegisters()); 4562086aeeaae12517475c22695a200be45495516549Ben Murdoch // Get return address and delta to inlined map check. 4563086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Operand(esp, 0 * kPointerSize)); 4564086aeeaae12517475c22695a200be45495516549Ben Murdoch __ sub(scratch, Operand(esp, 1 * kPointerSize)); 4565086aeeaae12517475c22695a200be45495516549Ben Murdoch if (FLAG_debug_code) { 4566086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmpb(Operand(scratch, 0), kCmpEdiImmediateByte1); 4567086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 1)"); 4568086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmpb(Operand(scratch, 1), kCmpEdiImmediateByte2); 4569086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 2)"); 4570086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4571086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(Operand(scratch, kDeltaToCmpImmediate), map); 4572086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Loop through the prototype chain of the object looking for the function 4575b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // prototype. 4576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset)); 4577257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop, is_instance, is_not_instance; 457880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 4579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(scratch, Operand(prototype)); 4580257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &is_instance, Label::kNear); 458144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 458244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(Operand(scratch), Immediate(factory->null_value())); 4583257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &is_not_instance, Label::kNear); 4584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); 4585b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); 458680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&loop); 458780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 458880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&is_instance); 4589086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasCallSiteInlineCheck()) { 4590086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Set(eax, Immediate(0)); 4591086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); 4592086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(Operand::StaticArray(scratch, 4593086aeeaae12517475c22695a200be45495516549Ben Murdoch times_pointer_size, roots_address), eax); 4594086aeeaae12517475c22695a200be45495516549Ben Murdoch } else { 4595086aeeaae12517475c22695a200be45495516549Ben Murdoch // Get return address and delta to inlined map check. 459644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, factory->true_value()); 4597086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Operand(esp, 0 * kPointerSize)); 4598086aeeaae12517475c22695a200be45495516549Ben Murdoch __ sub(scratch, Operand(esp, 1 * kPointerSize)); 4599086aeeaae12517475c22695a200be45495516549Ben Murdoch if (FLAG_debug_code) { 4600086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); 4601086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); 4602086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4603086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(Operand(scratch, kDeltaToMovImmediate), eax); 4604086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!ReturnTrueFalseObject()) { 4605086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Set(eax, Immediate(0)); 4606086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4607086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4608086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 460980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 461080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&is_not_instance); 4611086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasCallSiteInlineCheck()) { 4612086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 4613086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); 4614086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(Operand::StaticArray( 4615086aeeaae12517475c22695a200be45495516549Ben Murdoch scratch, times_pointer_size, roots_address), eax); 4616086aeeaae12517475c22695a200be45495516549Ben Murdoch } else { 4617086aeeaae12517475c22695a200be45495516549Ben Murdoch // Get return address and delta to inlined map check. 461844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, factory->false_value()); 4619086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Operand(esp, 0 * kPointerSize)); 4620086aeeaae12517475c22695a200be45495516549Ben Murdoch __ sub(scratch, Operand(esp, 1 * kPointerSize)); 4621086aeeaae12517475c22695a200be45495516549Ben Murdoch if (FLAG_debug_code) { 4622086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); 4623086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); 4624086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4625086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(Operand(scratch, kDeltaToMovImmediate), eax); 4626086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!ReturnTrueFalseObject()) { 4627086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 4628086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4629086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4630086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 4631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4632b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label object_not_null, object_not_null_or_smi; 4633b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_js_object); 4634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Before null, smi and string value checks, check that the rhs is a function 4635b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // as for a non-function rhs an exception needs to be thrown. 46363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(function, &slow); 4637b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); 4638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &slow); 4639b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4640b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Null is not instance of anything. 464144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(object, factory->null_value()); 4642b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_equal, &object_not_null); 4643b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 4644086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 4645b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4646b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&object_not_null); 4647b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Smi values is not instance of anything. 46483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(object, &object_not_null_or_smi); 4649b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 4650086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 4651b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4652b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&object_not_null_or_smi); 4653b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // String values is not instance of anything. 4654b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Condition is_string = masm->IsObjectStringType(object, scratch, scratch); 4655b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(NegateCondition(is_string), &slow); 4656b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 4657086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 465880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 465980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case: Go through the JavaScript implementation. 466080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 4661086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!ReturnTrueFalseObject()) { 4662086aeeaae12517475c22695a200be45495516549Ben Murdoch // Tail call the builtin which returns 0 or 1. 4663086aeeaae12517475c22695a200be45495516549Ben Murdoch if (HasArgsInRegisters()) { 4664086aeeaae12517475c22695a200be45495516549Ben Murdoch // Push arguments below return address. 4665086aeeaae12517475c22695a200be45495516549Ben Murdoch __ pop(scratch); 4666086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(object); 4667086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(function); 4668086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(scratch); 4669086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4670086aeeaae12517475c22695a200be45495516549Ben Murdoch __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 4671086aeeaae12517475c22695a200be45495516549Ben Murdoch } else { 4672086aeeaae12517475c22695a200be45495516549Ben Murdoch // Call the builtin and convert 0/1 to true/false. 4673086aeeaae12517475c22695a200be45495516549Ben Murdoch __ EnterInternalFrame(); 4674b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(object); 4675b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(function); 4676086aeeaae12517475c22695a200be45495516549Ben Murdoch __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); 4677086aeeaae12517475c22695a200be45495516549Ben Murdoch __ LeaveInternalFrame(); 4678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label true_value, done; 4679086aeeaae12517475c22695a200be45495516549Ben Murdoch __ test(eax, Operand(eax)); 4680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &true_value, Label::kNear); 468144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, factory->false_value()); 4682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 4683086aeeaae12517475c22695a200be45495516549Ben Murdoch __ bind(&true_value); 468444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, factory->true_value()); 4685086aeeaae12517475c22695a200be45495516549Ben Murdoch __ bind(&done); 4686086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 4687b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 468880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 468980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 469080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4691086aeeaae12517475c22695a200be45495516549Ben MurdochRegister InstanceofStub::left() { return eax; } 4692086aeeaae12517475c22695a200be45495516549Ben Murdoch 4693086aeeaae12517475c22695a200be45495516549Ben Murdoch 4694086aeeaae12517475c22695a200be45495516549Ben MurdochRegister InstanceofStub::right() { return edx; } 4695086aeeaae12517475c22695a200be45495516549Ben Murdoch 4696086aeeaae12517475c22695a200be45495516549Ben Murdoch 469780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenint CompareStub::MinorKey() { 469880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Encode the three parameters in a unique 16 bit value. To avoid duplicate 469980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stubs the never NaN NaN condition is only taken into account if the 470080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // condition is equals. 470180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(static_cast<unsigned>(cc_) < (1 << 12)); 470280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 470380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return ConditionField::encode(static_cast<unsigned>(cc_)) 470480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | RegisterField::encode(false) // lhs_ and rhs_ are not used 470580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | StrictField::encode(strict_) 470680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) 47070d5e116f6aee03185f237311a943491bb079a768Kristian Monsen | IncludeNumberCompareField::encode(include_number_compare_) 47080d5e116f6aee03185f237311a943491bb079a768Kristian Monsen | IncludeSmiCompareField::encode(include_smi_compare_); 470980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 471080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 471180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 471280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Unfortunately you have to run without snapshots to see most of these 471380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// names in the profile since most compare stubs end up in the snapshot. 47143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid CompareStub::PrintName(StringStream* stream) { 471580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 471680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const char* cc_name; 471780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen switch (cc_) { 471880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case less: cc_name = "LT"; break; 471980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case greater: cc_name = "GT"; break; 472080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case less_equal: cc_name = "LE"; break; 472180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case greater_equal: cc_name = "GE"; break; 472280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case equal: cc_name = "EQ"; break; 472380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case not_equal: cc_name = "NE"; break; 472480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen default: cc_name = "UnknownCondition"; break; 472580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 47263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch bool is_equality = cc_ == equal || cc_ == not_equal; 47273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("CompareStub_%s", cc_name); 47283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (strict_ && is_equality) stream->Add("_STRICT"); 47293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN"); 47303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (!include_number_compare_) stream->Add("_NO_NUMBER"); 47313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (!include_smi_compare_) stream->Add("_NO_SMI"); 473280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 473380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 473480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 473580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// ------------------------------------------------------------------------- 473680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharCodeAtGenerator 473780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 473880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { 473980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label flat_string; 474080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label ascii_string; 474180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label got_char_code; 474280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 474380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the receiver is a smi trigger the non-string case. 474480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 47453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(object_, receiver_not_string_); 474680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 474780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fetch the instance type of the receiver into result register. 474880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); 474980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); 475080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the receiver is not a string trigger the non-string case. 475180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(result_, Immediate(kIsNotStringMask)); 475280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, receiver_not_string_); 475380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 475480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the index is non-smi trigger the non-smi case. 475580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 47563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(index_, &index_not_smi_); 475780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 475880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Put smi-tagged index into scratch register. 475980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch_, index_); 476080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&got_smi_index_); 476180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 476280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for index out of range. 476380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(scratch_, FieldOperand(object_, String::kLengthOffset)); 476480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, index_out_of_range_); 476580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 476680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We need special handling for non-flat strings. 476780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSeqStringTag == 0); 476880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(result_, Immediate(kStringRepresentationMask)); 476980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &flat_string); 477080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 477180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle non-flat strings. 477280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(result_, Immediate(kIsConsStringMask)); 477380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &call_runtime_); 477480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 477580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ConsString. 477680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check whether the right hand side is the empty string (i.e. if 477780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // this is really a flat string in a cons string). If that is not 477880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the case we would rather go to the runtime system now to flatten 477980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the string. 478080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(object_, ConsString::kSecondOffset), 478144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(masm->isolate()->factory()->empty_string())); 478280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &call_runtime_); 478380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the first of the two strings and load its instance type. 478480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(object_, FieldOperand(object_, ConsString::kFirstOffset)); 478580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); 478680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); 478780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the first cons component is also non-flat, then go to runtime. 478880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSeqStringTag == 0); 478980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(result_, Immediate(kStringRepresentationMask)); 479080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &call_runtime_); 479180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 479280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for 1-byte or 2-byte string. 479380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&flat_string); 479480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kAsciiStringTag != 0); 479580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(result_, Immediate(kStringEncodingMask)); 479680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &ascii_string); 479780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 479880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // 2-byte string. 479980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the 2-byte character code into the result register. 480080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); 480180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_w(result_, FieldOperand(object_, 480280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch_, times_1, // Scratch is smi-tagged. 480380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SeqTwoByteString::kHeaderSize)); 480480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&got_char_code); 480580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 480680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ASCII string. 480780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the byte into the result register. 480880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&ascii_string); 480980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch_); 481080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(result_, FieldOperand(object_, 481180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch_, times_1, 481280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SeqAsciiString::kHeaderSize)); 481380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&got_char_code); 481480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(result_); 481580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&exit_); 481680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 481780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 481880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 481980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateSlow( 482080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen MacroAssembler* masm, const RuntimeCallHelper& call_helper) { 482180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough to CharCodeAt slow case"); 482280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 482380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Index is not a smi. 482480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&index_not_smi_); 482580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If index is a heap number, try converting it to an integer. 482644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CheckMap(index_, 482744f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()->factory()->heap_number_map(), 482844f0eee88ff00398ff7f715fab053374d808c90dSteve Block index_not_number_, 4829257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch DONT_DO_SMI_CHECK); 483080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 483180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(object_); 483280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(index_); 483380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(index_); // Consumed by runtime conversion function. 483480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (index_flags_ == STRING_INDEX_IS_NUMBER) { 483580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); 483680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 483780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); 483880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NumberToSmi discards numbers that are not exact integers. 483980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kNumberToSmi, 1); 484080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 484180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!scratch_.is(eax)) { 484280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Save the conversion result before the pop instructions below 484380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // have a chance to overwrite it. 484480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch_, eax); 484580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 484680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(index_); 484780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(object_); 484880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Reload the instance type. 484980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); 485080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); 485180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 485280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If index is still not a smi, it must be out of range. 485380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 48543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(scratch_, index_out_of_range_); 485580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Otherwise, return to the fast path. 485680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&got_smi_index_); 485780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 485880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call runtime. We get here when the receiver is a string and the 485980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // index is a number, but the code of getting the actual character 486080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // is too complex (e.g., when the string needs to be flattened). 486180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&call_runtime_); 486280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 486380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(object_); 486480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(index_); 486580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kStringCharCodeAt, 2); 486680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!result_.is(eax)) { 486780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, eax); 486880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 486980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 487080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&exit_); 487180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 487280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough from CharCodeAt slow case"); 487380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 487480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 487580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 487680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// ------------------------------------------------------------------------- 487780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharFromCodeGenerator 487880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 487980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { 488080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fast case of Heap::LookupSingleCharacterStringFromCode. 488180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 488280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiShiftSize == 0); 488380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); 488480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(code_, 488580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(kSmiTagMask | 488680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ((~String::kMaxAsciiCharCode) << kSmiTagSize))); 4887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &slow_case_); 488880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 488944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 489044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Set(result_, Immediate(factory->single_character_string_cache())); 489180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 489280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize == 1); 489380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiShiftSize == 0); 489480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // At this point code register contains smi tagged ascii char code. 489580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, FieldOperand(result_, 489680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen code_, times_half_pointer_size, 489780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize)); 489844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(result_, factory->undefined_value()); 4899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &slow_case_); 490080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&exit_); 490180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 490280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 490380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 490480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateSlow( 490580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen MacroAssembler* masm, const RuntimeCallHelper& call_helper) { 490680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough to CharFromCode slow case"); 490780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 490880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow_case_); 490980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 491080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(code_); 491180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kCharFromCode, 1); 491280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!result_.is(eax)) { 491380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, eax); 491480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 491580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 491680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&exit_); 491780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 491880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough from CharFromCode slow case"); 491980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 492080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 492180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 492280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// ------------------------------------------------------------------------- 492380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharAtGenerator 492480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 492580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateFast(MacroAssembler* masm) { 492680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_code_at_generator_.GenerateFast(masm); 492780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_from_code_generator_.GenerateFast(masm); 492880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 492980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 493080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 493180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateSlow( 493280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen MacroAssembler* masm, const RuntimeCallHelper& call_helper) { 493380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_code_at_generator_.GenerateSlow(masm, call_helper); 493480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_from_code_generator_.GenerateSlow(masm, call_helper); 493580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 493680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 493780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 493880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringAddStub::Generate(MacroAssembler* masm) { 49399ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label string_add_runtime, call_builtin; 49409ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Builtins::JavaScript builtin_id = Builtins::ADD; 494180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 494280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the two arguments. 494380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. 494480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. 494580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 494680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure that both arguments are strings if not known in advance. 49479ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick if (flags_ == NO_STRING_ADD_FLAGS) { 49483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &string_add_runtime); 494980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx); 495080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &string_add_runtime); 495180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 495280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // First argument is a a string, test second. 49533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(edx, &string_add_runtime); 495480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); 495580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &string_add_runtime); 49569ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick } else { 49579ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Here at least one of the arguments is definitely a string. 49589ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // We convert the one that is not known to be a string. 49599ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { 49609ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); 49619ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi, 49629ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick &call_builtin); 49639ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick builtin_id = Builtins::STRING_ADD_RIGHT; 49649ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { 49659ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); 49669ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick GenerateConvertArgument(masm, 1 * kPointerSize, edx, ebx, ecx, edi, 49679ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick &call_builtin); 49689ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick builtin_id = Builtins::STRING_ADD_LEFT; 49699ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick } 497080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 497180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 497280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both arguments are strings. 497380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first string 497480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: second string 497580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if either of the strings are empty. In that case return the other. 4976257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label second_not_zero_length, both_not_zero_length; 497780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); 497880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 497980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Operand(ecx)); 4980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &second_not_zero_length, Label::kNear); 498180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Second string is empty, result is first string which is already in eax. 498244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 498344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 498480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 498580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&second_not_zero_length); 498680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); 498780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 498880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ebx, Operand(ebx)); 4989257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &both_not_zero_length, Label::kNear); 499080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // First string is empty, result is second string which is in edx. 499180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, edx); 499244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 499380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 499480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 499580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both strings are non-empty. 499680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first string 499780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: length of first string as a smi 499880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: length of second string as a smi 499980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: second string 500080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Look at the length of the result of adding the two strings. 500180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label string_add_flat_result, longer_than_two; 500280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&both_not_zero_length); 500380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(ebx, Operand(ecx)); 500480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength); 500580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle exceptionally long strings in the runtime system. 500680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(overflow, &string_add_runtime); 500744f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Use the symbol table when adding two one character strings, as it 500844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // helps later optimizations to return a symbol here. 500980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand(ebx), Immediate(Smi::FromInt(2))); 501080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &longer_than_two); 501180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 501280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that both strings are non-external ascii strings. 501380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, 501480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &string_add_runtime); 501580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 50169ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Get the two characters forming the new string. 501780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); 501880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); 501980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 502080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try to lookup two character string in symbol table. If it is not found 502180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // just allocate a new one. 50229ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label make_two_character_string, make_two_character_string_no_reload; 502380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateTwoCharacterSymbolTableProbe( 50249ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick masm, ebx, ecx, eax, edx, edi, 50259ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick &make_two_character_string_no_reload, &make_two_character_string); 502644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 502780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 502880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 50299ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Allocate a two character string. 503080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&make_two_character_string); 50319ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Reload the arguments. 50329ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. 50339ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. 50349ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Get the two characters forming the new string. 50359ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); 50369ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); 50379ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(&make_two_character_string_no_reload); 503844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_make_two_char(), 1); 50399ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ AllocateAsciiString(eax, // Result. 50409ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 2, // Length. 50419ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick edi, // Scratch 1. 50429ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick edx, // Scratch 2. 50439ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick &string_add_runtime); 50449ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Pack both characters in ebx. 50459ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ shl(ecx, kBitsPerByte); 50469ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ or_(ebx, Operand(ecx)); 50479ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Set the characters in the new string. 50489ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx); 504944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 50509ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ ret(2 * kPointerSize); 505180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 505280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&longer_than_two); 505380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if resulting string will be flat. 505480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand(ebx), Immediate(Smi::FromInt(String::kMinNonFlatLength))); 505580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(below, &string_add_flat_result); 505680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 505780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If result is not supposed to be flat allocate a cons string object. If both 505880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // strings are ascii the result is an ascii cons string. 505980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_ascii, allocated, ascii_data; 506080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); 506180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); 506280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 506380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); 506480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(ecx, Operand(edi)); 506580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag); 506680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Immediate(kAsciiStringTag)); 506780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &non_ascii); 506880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&ascii_data); 506980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate an acsii cons string. 507080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); 507180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&allocated); 507280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fill the fields of the cons string. 507380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) __ AbortIfNotSmi(ebx); 507480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); 507580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), 507680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(String::kEmptyHashField)); 507780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); 507880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); 507980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, ecx); 508044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 508180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 508280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_ascii); 508380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // At least one of the strings is two-byte. Check whether it happens 508480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // to contain only ascii characters. 508580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: first instance type AND second instance type. 508680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: second instance type. 508780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Immediate(kAsciiDataHintMask)); 508880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &ascii_data); 508980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 509080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 509180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(edi, Operand(ecx)); 509280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); 509380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(edi, kAsciiStringTag | kAsciiDataHintTag); 509480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); 509580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &ascii_data); 509680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate a two byte cons string. 509780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateConsString(ecx, edi, no_reg, &string_add_runtime); 509880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&allocated); 509980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 510080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle creating a flat result. First check that both strings are not 510180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // external strings. 510280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first string 510380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: length of resulting flat string as a smi 510480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: second string 510580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&string_add_flat_result); 510680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 510780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 510880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(ecx, kStringRepresentationMask); 510980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(ecx, kExternalStringTag); 511080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &string_add_runtime); 511180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 511280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 511380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(ecx, kStringRepresentationMask); 511480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(ecx, kExternalStringTag); 511580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &string_add_runtime); 511680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Now check if both strings are ascii strings. 511780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first string 511880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: length of resulting flat string as a smi 511980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: second string 512080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_ascii_string_add_flat_result; 512180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag); 512280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 512380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); 512480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &non_ascii_string_add_flat_result); 512580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 512680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); 512780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &string_add_runtime); 512880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 512980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both strings are ascii strings. As they are short they are both flat. 513080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: length of resulting flat string as a smi 513180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ebx); 513280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime); 513380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 513480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, eax); 513580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 513680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 513780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load first argument and locate first character. 513880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 2 * kPointerSize)); 513980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 514080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edi); 514180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 514280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 514380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: first character of result 514480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: first char of first argument 514580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: length of first argument 514680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); 514780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load second argument and locate first character. 514880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 1 * kPointerSize)); 514980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 515080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edi); 515180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 515280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 515380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: next character of result 515480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: first char of second argument 515580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: length of second argument 515680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); 515744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 515880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 515980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 516080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle creating a flat two byte result. 516180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first string - known to be two byte 516280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: length of resulting flat string as a smi 516380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: second string 516480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_ascii_string_add_flat_result); 516580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 516680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); 516780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &string_add_runtime); 516880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both strings are two byte strings. As they are short they are both 516980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // flat. 517080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ebx); 517180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); 517280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 517380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, eax); 517480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 517580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(ecx), 517680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 517780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load first argument and locate first character. 517880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 2 * kPointerSize)); 517980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 518080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edi); 518180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), 518280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 518380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 518480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: first character of result 518580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: first char of first argument 518680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: length of first argument 518780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); 518880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load second argument and locate first character. 518980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 1 * kPointerSize)); 519080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 519180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edi); 519280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 519380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 519480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: next character of result 519580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: first char of second argument 519680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: length of second argument 519780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); 519844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 519980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 520080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 520180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump to runtime to add the two strings. 520280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&string_add_runtime); 520380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kStringAdd, 2, 1); 52049ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 52059ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick if (call_builtin.is_linked()) { 52069ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(&call_builtin); 52079ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); 52089ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick } 52099ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick} 52109ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 52119ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 52129ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrickvoid StringAddStub::GenerateConvertArgument(MacroAssembler* masm, 52139ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick int stack_offset, 52149ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Register arg, 52159ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Register scratch1, 52169ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Register scratch2, 52179ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Register scratch3, 52189ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label* slow) { 52199ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // First check if the argument is already a string. 52209ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label not_string, done; 52213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(arg, ¬_string); 52229ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); 52239ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ j(below, &done); 52249ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 52259ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Check the number to string cache. 52269ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label not_cached; 52279ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(¬_string); 52289ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Puts the cached result into scratch1. 52299ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick NumberToStringStub::GenerateLookupNumberStringCache(masm, 52309ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick arg, 52319ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick scratch1, 52329ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick scratch2, 52339ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick scratch3, 52349ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick false, 52359ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick ¬_cached); 52369ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(arg, scratch1); 52379ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(Operand(esp, stack_offset), arg); 52389ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ jmp(&done); 52399ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 52409ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Check if the argument is a safe string wrapper. 52419ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(¬_cached); 52423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(arg, slow); 52439ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1); // map -> scratch1. 52449ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ j(not_equal, slow); 52459ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ test_b(FieldOperand(scratch1, Map::kBitField2Offset), 52469ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 1 << Map::kStringWrapperSafeForDefaultValueOf); 52479ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ j(zero, slow); 52489ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(arg, FieldOperand(arg, JSValue::kValueOffset)); 52499ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(Operand(esp, stack_offset), arg); 52509ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 52519ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(&done); 525280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 525380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 525480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 525580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharacters(MacroAssembler* masm, 525680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register dest, 525780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register src, 525880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register count, 525980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch, 526080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool ascii) { 5261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop; 526280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 526380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // This loop just copies one character at a time, as it is only used for very 526480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // short strings. 526580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (ascii) { 526680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_b(scratch, Operand(src, 0)); 526780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_b(Operand(dest, 0), scratch); 526880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(src), Immediate(1)); 526980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(dest), Immediate(1)); 527080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 527180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_w(scratch, Operand(src, 0)); 527280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_w(Operand(dest, 0), scratch); 527380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(src), Immediate(2)); 527480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(dest), Immediate(2)); 527580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 527680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(count), Immediate(1)); 527780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &loop); 527880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 527980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 528080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 528180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, 528280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register dest, 528380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register src, 528480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register count, 528580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch, 528680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool ascii) { 528780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy characters using rep movs of doublewords. 528880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The destination is aligned on a 4 byte boundary because we are 528980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // copying to the beginning of a newly allocated string. 529080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(dest.is(edi)); // rep movs destination 529180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(src.is(esi)); // rep movs source 529280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(count.is(ecx)); // rep movs count 529380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(dest)); 529480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(src)); 529580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(count)); 529680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 529780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Nothing to do for zero characters. 529880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label done; 529980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(count, Operand(count)); 530080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &done); 530180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 530280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make count the number of bytes to copy. 530380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!ascii) { 530480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(count, 1); 530580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 530680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 530780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Don't enter the rep movs if there are less than 4 bytes to copy. 5308257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label last_bytes; 530980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(count, Immediate(~3)); 5310257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &last_bytes, Label::kNear); 531180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 531280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy from edi to esi using rep movs instruction. 531380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, count); 531480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sar(count, 2); // Number of doublewords to copy. 531580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cld(); 531680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ rep_movs(); 531780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 531880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find number of bytes left. 531980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(count, scratch); 532080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(count, 3); 532180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 532280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if there are more bytes to copy. 532380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&last_bytes); 532480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(count, Operand(count)); 532580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &done); 532680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 532780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy remaining characters. 5328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop; 532980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 533080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_b(scratch, Operand(src, 0)); 533180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_b(Operand(dest, 0), scratch); 533280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(src), Immediate(1)); 533380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(dest), Immediate(1)); 533480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(count), Immediate(1)); 533580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &loop); 533680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 533780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 533880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 533980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 534080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 534180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, 534280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register c1, 534380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register c2, 534480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 534580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 534680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch3, 53479ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label* not_probed, 534880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_found) { 534980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Register scratch3 is the general scratch register in this function. 535080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch = scratch3; 535180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 535280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure that both characters are not digits as such strings has a 535380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // different hash algorithm. Don't try to look for these in the symbol table. 5354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_array_index; 535580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, c1); 535680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(scratch), Immediate(static_cast<int>('0'))); 535780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0'))); 5358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above, ¬_array_index, Label::kNear); 535980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, c2); 536080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(scratch), Immediate(static_cast<int>('0'))); 536180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0'))); 53629ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ j(below_equal, not_probed); 536380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 536480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_array_index); 536580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate the two character string hash. 536680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash = scratch1; 536780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateHashInit(masm, hash, c1, scratch); 536880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateHashAddCharacter(masm, hash, c2, scratch); 536980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateHashGetHash(masm, hash, scratch); 537080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 537180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Collect the two characters in a register. 537280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register chars = c1; 537380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(c2, kBitsPerByte); 537480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ or_(chars, Operand(c2)); 537580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 537680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 537780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash: hash of two character string. 537880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 537980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the symbol table. 538080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register symbol_table = c2; 538144f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference roots_address = 538244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::roots_address(masm->isolate()); 538380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex)); 538480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(symbol_table, 538580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Operand::StaticArray(scratch, times_pointer_size, roots_address)); 538680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 538780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate capacity mask from the symbol table capacity. 538880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register mask = scratch2; 538980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); 539080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(mask); 539180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(mask), Immediate(1)); 539280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 539380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Registers 539480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 539580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash: hash of two character string 539680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // symbol_table: symbol table 539780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // mask: capacity mask 539880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // scratch: - 539980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 540080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Perform a number of probes in the symbol table. 540180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kProbes = 4; 540280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label found_in_symbol_table; 540380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label next_probe[kProbes], next_probe_pop_mask[kProbes]; 540480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = 0; i < kProbes; i++) { 540580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate entry in symbol table. 540680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 540780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (i > 0) { 540880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(scratch), Immediate(SymbolTable::GetProbeOffset(i))); 540980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 541080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(scratch, Operand(mask)); 541180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 541280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the entry from the symbol table. 541380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register candidate = scratch; // Scratch register contains candidate. 541480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(SymbolTable::kEntrySize == 1); 541580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(candidate, 541680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(symbol_table, 541780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch, 541880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_pointer_size, 541980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SymbolTable::kElementsStartOffset)); 542080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 542180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If entry is undefined no string with this hash can be found. 542244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 542344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(candidate, factory->undefined_value()); 542480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, not_found); 542544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(candidate, factory->null_value()); 542644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ j(equal, &next_probe[i]); 542780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 542880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If length is not 2 the string is not a candidate. 542980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(candidate, String::kLengthOffset), 543080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(Smi::FromInt(2))); 543180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &next_probe[i]); 543280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 543380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // As we are out of registers save the mask on the stack and use that 543480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // register as a temporary. 543580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(mask); 543680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register temp = mask; 543780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 543880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the candidate is a non-external ascii string. 543980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); 544080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); 544180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfInstanceTypeIsNotSequentialAscii( 544280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen temp, temp, &next_probe_pop_mask[i]); 544380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 544480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the two characters match. 544580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); 544680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(temp, 0x0000ffff); 544780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(chars, Operand(temp)); 544880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &found_in_symbol_table); 544980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&next_probe_pop_mask[i]); 545080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(mask); 545180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&next_probe[i]); 545280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 545380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 545480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // No matching 2 character string found by probing. 545580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(not_found); 545680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 545780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Scratch register contains result when we fall through to here. 545880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register result = scratch; 545980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&found_in_symbol_table); 546080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(mask); // Pop saved mask from the stack. 546180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!result.is(eax)) { 546280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, result); 546380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 546480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 546580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 546680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 546780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashInit(MacroAssembler* masm, 546880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 546980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register character, 547080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 547180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash = character + (character << 10); 547280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(hash, character); 547380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(hash, 10); 547480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(hash, Operand(character)); 547580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 6; 547680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 547780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sar(scratch, 6); 547880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(hash, Operand(scratch)); 547980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 548080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 548180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 548280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, 548380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 548480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register character, 548580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 548680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += character; 548780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(hash, Operand(character)); 548880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 10; 548980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 549080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(scratch, 10); 549180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(hash, Operand(scratch)); 549280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 6; 549380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 549480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sar(scratch, 6); 549580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(hash, Operand(scratch)); 549680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 549780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 549880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 549980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashGetHash(MacroAssembler* masm, 550080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 550180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 550280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 3; 550380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 550480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(scratch, 3); 550580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(hash, Operand(scratch)); 550680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 11; 550780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 550880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sar(scratch, 11); 550980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(hash, Operand(scratch)); 551080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 15; 551180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 551280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(scratch, 15); 551380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(hash, Operand(scratch)); 551480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 551580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // if (hash == 0) hash = 27; 5516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label hash_not_zero; 551780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(hash, Operand(hash)); 5518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &hash_not_zero, Label::kNear); 551980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(hash, Immediate(27)); 552080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&hash_not_zero); 552180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 552280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 552380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 552480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid SubStringStub::Generate(MacroAssembler* masm) { 552580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 552680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 552780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 552880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[0]: return address 552980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[4]: to 553080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[8]: from 553180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[12]: string 553280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 553380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure first argument is a string. 553480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, 3 * kPointerSize)); 553580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 55363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &runtime); 553780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); 553880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(NegateCondition(is_string), &runtime); 553980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 554080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: string 554180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: instance type 554280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 554380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate length of sub string using the smi values. 554480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label result_longer_than_two; 554580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index. 55463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(ecx, &runtime); 554780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index. 55483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(edx, &runtime); 554980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(ecx, Operand(edx)); 555080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(ecx, FieldOperand(eax, String::kLengthOffset)); 555180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label return_eax; 555280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &return_eax); 555380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Special handling of sub-strings of length 1 and 2. One character strings 555480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // are handled in the runtime system (looked up in the single character 555580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // cache). Two character strings are looked for in the symbol cache. 555680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ecx); // Result length is no longer smi. 555780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(ecx, 2); 555880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(greater, &result_longer_than_two); 555980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(less, &runtime); 556080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 556180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Sub string of length 2 requested. 556280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: string 556380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: instance type 556480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: sub string length (value is 2) 556580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: from index (smi) 556680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &runtime); 556780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 556880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the two characters forming the sub string. 556980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edx); // From index is no longer smi. 557080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ebx, FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize)); 557180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, 557280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize + 1)); 557380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 557480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try to lookup two character string in symbol table. 557580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label make_two_character_string; 557680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateTwoCharacterSymbolTableProbe( 55779ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick masm, ebx, ecx, eax, edx, edi, 55789ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick &make_two_character_string, &make_two_character_string); 557980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 558080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 558180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&make_two_character_string); 558280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Setup registers for allocating the two character string. 558380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, 3 * kPointerSize)); 558480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 558580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 558680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(ecx, Immediate(2)); 558780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 558880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&result_longer_than_two); 558980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: string 559080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: instance type 559180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result string length 559280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for flat ascii string 559380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_ascii_flat; 559480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &non_ascii_flat); 559580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 559680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate the result. 559780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime); 559880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 559980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 560080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result string length 560180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, esi); // esi used by following code. 560280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 560380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, eax); 560480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 560580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load string argument and locate character of sub string start. 560680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(esi, Operand(esp, 3 * kPointerSize)); 560780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(esi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 560880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(esp, 2 * kPointerSize)); // from 560980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ebx); 561080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(esi, Operand(ebx)); 561180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 561280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 561380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result length 561480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: original value of esi 561580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: first character of result 561680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: character of sub string start 561780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); 561880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(esi, edx); // Restore esi. 561944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 562044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->sub_string_native(), 1); 562180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 562280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 562380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_ascii_flat); 562480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: string 562580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: instance type & kStringRepresentationMask | kStringEncodingMask 562680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result string length 562780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for flat two byte string 562880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(ebx, kSeqStringTag | kTwoByteStringTag); 562980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 563080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 563180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate the result. 563280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime); 563380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 563480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 563580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result string length 563680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, esi); // esi used by following code. 563780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 563880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, eax); 563980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edi), 564080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 564180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load string argument and locate character of sub string start. 564280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(esi, Operand(esp, 3 * kPointerSize)); 564380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(esi), 564480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 564580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(esp, 2 * kPointerSize)); // from 564680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // As from is a smi it is 2 times the value which matches the size of a two 564780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // byte character. 564880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 564980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 565080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(esi, Operand(ebx)); 565180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 565280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 565380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result length 565480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: original value of esi 565580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: first character of result 565680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: character of sub string start 565780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); 565880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(esi, edx); // Restore esi. 565980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 566080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&return_eax); 566144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->sub_string_native(), 1); 566280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 566380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 566480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump to runtime to create the sub string. 566580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 566680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kSubString, 3, 1); 566780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 566880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 566980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, 5671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left, 5672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right, 5673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch1, 5674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch2) { 5675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register length = scratch1; 5676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare lengths. 5678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label strings_not_equal, check_zero_length; 5679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(length, FieldOperand(left, String::kLengthOffset)); 5680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(length, FieldOperand(right, String::kLengthOffset)); 5681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &check_zero_length, Label::kNear); 5682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&strings_not_equal); 5683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL))); 5684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 5685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the length is zero. 5687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label compare_chars; 5688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&check_zero_length); 5689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 5690257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(length, Operand(length)); 5691257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &compare_chars, Label::kNear); 5692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 5693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 5694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare characters. 5696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&compare_chars); 5697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2, 5698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch &strings_not_equal, Label::kNear); 5699257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Characters are equal. 5701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 5702257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 5703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 5704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 570680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, 570780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register left, 570880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register right, 570980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 571080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 571180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch3) { 571244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 571344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_compare_native(), 1); 571480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 571580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find minimum length. 5716257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label left_shorter; 571780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); 571880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch3, scratch1); 571980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); 572080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 572180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register length_delta = scratch3; 572280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(less_equal, &left_shorter, Label::kNear); 572480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Right string is shorter. Change scratch1 to be length of right string. 572580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(scratch1, Operand(length_delta)); 572680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&left_shorter); 572780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 572880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register min_length = scratch1; 572980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 573080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If either length is zero, just compare lengths. 5731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label compare_lengths; 573280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(min_length, Operand(min_length)); 5733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &compare_lengths, Label::kNear); 573480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare characters. 5736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label result_not_equal; 5737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2, 5738257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch &result_not_equal, Label::kNear); 573980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 574080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compare lengths - strings up to min-length are equal. 574180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&compare_lengths); 574280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(length_delta, Operand(length_delta)); 5743257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &result_not_equal, Label::kNear); 574480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 574580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is EQUAL. 574680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(EQUAL == 0); 574780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 574880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 574980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 575080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5751257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label result_greater; 575280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&result_not_equal); 5753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(greater, &result_greater, Label::kNear); 575480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 575580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is LESS. 575680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(LESS))); 575780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 575880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 575980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is GREATER. 576080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&result_greater); 576180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(GREATER))); 576280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 576380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 576480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 576580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateAsciiCharsCompareLoop( 5767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 5768257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left, 5769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right, 5770257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register length, 5771257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch, 5772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* chars_not_equal, 5773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance chars_not_equal_near) { 5774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Change index to run from -length to -1 by adding length to string 5775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // start. This means that loop ends when index reaches zero, which 5776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // doesn't need an additional compare. 5777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiUntag(length); 5778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(left, 5779257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize)); 5780257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(right, 5781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize)); 5782257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ neg(length); 5783257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register index = length; // index = -length; 5784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5785257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare loop. 5786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop; 5787257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&loop); 5788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov_b(scratch, Operand(left, index, times_1, 0)); 5789257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmpb(scratch, Operand(right, index, times_1, 0)); 5790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, chars_not_equal, chars_not_equal_near); 5791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(Operand(index), Immediate(1)); 5792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &loop); 5793257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 5794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5795257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 579680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::Generate(MacroAssembler* masm) { 579780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 579880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 579980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 580080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[0]: return address 580180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[4]: right string 580280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[8]: left string 580380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 580480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 2 * kPointerSize)); // left 580580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, 1 * kPointerSize)); // right 580680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_same; 580880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, Operand(eax)); 5809257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, ¬_same, Label::kNear); 581080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(EQUAL == 0); 581180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 581280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 581344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(masm->isolate()->counters()->string_compare_native(), 1); 581480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 581580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 581680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_same); 581780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 581880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that both objects are sequential ascii strings. 581980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); 582080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 582180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compare flat ascii strings. 582280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Drop arguments from the stack. 582380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ecx); 582480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(esp), Immediate(2 * kPointerSize)); 582580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ecx); 582680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); 582780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 582880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 582980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // tagged as a small integer. 583080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 583180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 583280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 583380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5834b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5835b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateSmis(MacroAssembler* masm) { 5836b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(state_ == CompareIC::SMIS); 5837257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 5838b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(edx)); 5839b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ or_(ecx, Operand(eax)); 58403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(ecx, &miss, Label::kNear); 5841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (GetCondition() == equal) { 5843b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // For equality we do not care about the sign of the result. 5844b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(eax, Operand(edx)); 5845b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 5846257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done; 5847b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(edx, Operand(eax)); 5848257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(no_overflow, &done, Label::kNear); 5849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Correct sign of result in case of overflow. 5850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ not_(edx); 5851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&done); 5852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, edx); 5853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 5854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 5855b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5856b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&miss); 5857b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateMiss(masm); 5858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 5859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5860b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5861b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { 5862b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(state_ == CompareIC::HEAP_NUMBERS); 5863b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label generic_stub; 5865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label unordered; 5866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 5867b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(edx)); 5868b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ and_(ecx, Operand(eax)); 58693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(ecx, &generic_stub, Label::kNear); 5870b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5871b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx); 5872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 5873b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); 5874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 5875b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5876b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Inlining the double comparison and falling back to the general compare 5877b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // stub if NaN is involved or SS2 or CMOV is unsupported. 58788b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { 5879b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope scope1(SSE2); 5880b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope scope2(CMOV); 5881b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5882b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Load left and right operand 5883b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 5884b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 5885b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5886b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Compare operands 5887b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm0, xmm1); 5888b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5889b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Don't base result on EFLAGS when a NaN is involved. 5890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(parity_even, &unordered, Label::kNear); 5891b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5892b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Return a result of -1, 0, or 1, based on EFLAGS. 5893b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Performing mov, because xor would destroy the flag register. 5894b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, 0); // equal 5895b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Immediate(Smi::FromInt(1))); 5896b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmov(above, eax, Operand(ecx)); 5897b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Immediate(Smi::FromInt(-1))); 5898b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmov(below, eax, Operand(ecx)); 5899b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 5900b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5901b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&unordered); 5902b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 5903b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5904b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); 5905b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&generic_stub); 5906b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); 5907b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5908b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&miss); 5909b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateMiss(masm); 5910b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 5911b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5912b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateSymbols(MacroAssembler* masm) { 5914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(state_ == CompareIC::SYMBOLS); 5915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(GetCondition() == equal); 5916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 5918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = edx; 5919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = eax; 5920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp1 = ecx; 5921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp2 = ebx; 5922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are heap objects. 5924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 5925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp1, Operand(left)); 5926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 5927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(tmp1, Operand(right)); 59283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(tmp1, &miss, Label::kNear); 5929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are symbols. 5931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); 5932257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); 5933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); 5934257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); 5935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSymbolTag != 0); 5936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(tmp1, Operand(tmp2)); 5937257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(tmp1, Immediate(kIsSymbolMask)); 5938257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &miss, Label::kNear); 5939257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Symbols are compared by identity. 5941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done; 5942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(left, Operand(right)); 5943257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Make sure eax is non-zero. At this point input operands are 5944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // guaranteed to be non-zero. 5945257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(right.is(eax)); 5946257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &done, Label::kNear); 5947257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(EQUAL == 0); 5948257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 5949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 5950257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&done); 5951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 5952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&miss); 5954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateMiss(masm); 5955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 5956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5958257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateStrings(MacroAssembler* masm) { 5959257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(state_ == CompareIC::STRINGS); 5960257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(GetCondition() == equal); 5961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 5962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 5964257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = edx; 5965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = eax; 5966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp1 = ecx; 5967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp2 = ebx; 5968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp3 = edi; 5969257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5970257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are heap objects. 5971257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp1, Operand(left)); 5972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 5973257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(tmp1, Operand(right)); 59743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(tmp1, &miss); 5975257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5976257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are strings. This leaves the instance 5977257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // types loaded in tmp1 and tmp2. 5978257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); 5979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); 5980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); 5981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); 5982257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp3, tmp1); 5983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kNotStringTag != 0); 5984257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ or_(tmp3, Operand(tmp2)); 5985257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(tmp3, Immediate(kIsNotStringMask)); 5986257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &miss); 5987257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Fast check for identical strings. 5989257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_same; 5990257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(left, Operand(right)); 5991257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, ¬_same, Label::kNear); 5992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(EQUAL == 0); 5993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 5994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 5995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 5996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle not identical strings. 5998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(¬_same); 5999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both strings are symbols. If they are, we're done 6001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // because we already know they are not identical. 6002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label do_compare; 6003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSymbolTag != 0); 6004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(tmp1, Operand(tmp2)); 6005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(tmp1, Immediate(kIsSymbolMask)); 6006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &do_compare, Label::kNear); 6007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Make sure eax is non-zero. At this point input operands are 6008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // guaranteed to be non-zero. 6009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(right.is(eax)); 6010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 6011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both strings are sequential ASCII. 6013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label runtime; 6014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&do_compare); 6015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime); 6016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare flat ASCII strings. Returns when done. 6018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringCompareStub::GenerateFlatAsciiStringEquals( 6019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch masm, left, right, tmp1, tmp2); 6020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle more complex cases in runtime. 6022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&runtime); 6023257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(tmp1); // Return address. 6024257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(left); 6025257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(right); 6026257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(tmp1); 6027257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ TailCallRuntime(Runtime::kStringEquals, 2, 1); 6028257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6029257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&miss); 6030257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateMiss(masm); 6031257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6032257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6034b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateObjects(MacroAssembler* masm) { 6035b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(state_ == CompareIC::OBJECTS); 6036257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 6037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(edx)); 6038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ and_(ecx, Operand(eax)); 60393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(ecx, &miss, Label::kNear); 6040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); 6042257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 6043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); 6044257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 6045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(GetCondition() == equal); 6047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(eax, Operand(edx)); 6048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 6049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&miss); 6051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateMiss(masm); 6052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 6053b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateMiss(MacroAssembler* masm) { 6056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Save the registers. 6057b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(ecx); 6058b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(edx); 6059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(eax); 6060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(ecx); 6061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Call the runtime system in a fresh internal frame. 606344f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss), 606444f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 6065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ EnterInternalFrame(); 6066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(edx); 6067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(eax); 6068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(op_))); 6069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CallExternalReference(miss, 3); 6070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ LeaveInternalFrame(); 6071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Compute the entry point of the rewritten stub. 6073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ lea(edi, FieldOperand(eax, Code::kHeaderSize)); 6074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Restore registers. 6076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(ecx); 6077b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(eax); 6078b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(edx); 6079b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(ecx); 6080b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6081b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Do a tail call to the rewritten stub. 6082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(Operand(edi)); 6083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 6084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6086257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Helper function used to check that the dictionary doesn't contain 6087257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// the property. This function may return false negatives, so miss_label 6088257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// must always call a backup property check that is complete. 6089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// This function is safe to call if the receiver has fast properties. 6090257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Name must be a symbol and receiver must be a heap object. 6091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben MurdochMaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup( 6092257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 6093257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* miss, 6094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* done, 6095257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register properties, 6096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch String* name, 6097257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register r0) { 6098257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(name->IsSymbol()); 6099257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6100257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If names of slots in range from 1 to kProbes - 1 for the hash value are 6101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // not equal to the name and kProbes-th slot is not used (its name is the 6102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // undefined value), it guarantees the hash table doesn't contain the 6103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // property. It's true even if some slots represent deleted properties 6104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // (their names are the null value). 6105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = 0; i < kInlinedProbes; i++) { 6106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 6107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register index = r0; 6108257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Capacity is smi 2^n. 6109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(index, FieldOperand(properties, kCapacityOffset)); 6110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ dec(index); 6111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(Operand(index), 6112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Immediate(Smi::FromInt(name->Hash() + 6113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionary::GetProbeOffset(i)))); 6114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the entry size. 6116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 6117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. 6118257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register entity_name = r0; 6119257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Having undefined at this place means the name is not contained. 6120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT_EQ(kSmiTagSize, 1); 6121257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(entity_name, Operand(properties, index, times_half_pointer_size, 6122257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kElementsStartOffset - kHeapObjectTag)); 6123257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(entity_name, masm->isolate()->factory()->undefined_value()); 6124257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, done); 6125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6126257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Stop if found the property. 6127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(entity_name, Handle<String>(name)); 6128257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, miss); 6129257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6130257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the entry name is not a symbol. 6131257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); 6132257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset), 6133257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kIsSymbolMask); 6134257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, miss); 6135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionaryLookupStub stub(properties, 6138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 6139257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 6140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionaryLookupStub::NEGATIVE_LOOKUP); 6141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(Immediate(Handle<Object>(name))); 6142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(Immediate(name->Hash())); 6143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MaybeObject* result = masm->TryCallStub(&stub); 6144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (result->IsFailure()) return result; 6145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(r0, Operand(r0)); 6146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, miss); 6147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(done); 6148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch return result; 6149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6151257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Probe the string dictionary in the |elements| register. Jump to the 6153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// |done| label if a property with the given name is found leaving the 6154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// index into the dictionary in |r0|. Jump to the |miss| label 6155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// otherwise. 6156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, 6157257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* miss, 6158257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* done, 6159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register elements, 6160257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register name, 6161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register r0, 6162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register r1) { 6163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Assert that name contains a string. 6164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (FLAG_debug_code) __ AbortIfNotString(name); 6165257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r1, FieldOperand(elements, kCapacityOffset)); 6167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(r1, kSmiTagSize); // convert smi to int 6168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ dec(r1); 6169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Generate an unrolled loop that performs a few probes before 6171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // giving up. Measurements done on Gmail indicate that 2 probes 6172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // cover ~93% of loads from dictionaries. 6173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = 0; i < kInlinedProbes; i++) { 6174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 6175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); 6176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(r0, String::kHashShift); 6177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i > 0) { 6178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i))); 6179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(r0, Operand(r1)); 6181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6182257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the entry size. 6183257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 6184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3 6185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6186257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the key is identical to the name. 6187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(name, Operand(elements, 6188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 6189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch times_4, 6190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kElementsStartOffset - kHeapObjectTag)); 6191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, done); 6192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionaryLookupStub stub(elements, 6195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r1, 6196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 6197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch POSITIVE_LOOKUP); 6198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(name); 6199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); 6200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(r0, String::kHashShift); 6201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(r0); 6202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallStub(&stub); 6203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(r1, Operand(r1)); 6205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, miss); 6206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(done); 6207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6209257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6210257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::Generate(MacroAssembler* masm) { 6211257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Stack frame on entry: 6212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // esp[0 * kPointerSize]: return address. 6213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // esp[1 * kPointerSize]: key's hash. 6214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // esp[2 * kPointerSize]: key. 6215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers: 6216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // dictionary_: StringDictionary to probe. 6217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // result_: used as scratch. 6218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // index_: will hold an index of entry if lookup is successful. 6219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // might alias with result_. 6220257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Returns: 6221257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // result_ is zero if lookup failed, non zero otherwise. 6222257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6223257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label in_dictionary, maybe_in_dictionary, not_in_dictionary; 6224257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6225257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch = result_; 6226257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6227257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset)); 6228257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ dec(scratch); 6229257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiUntag(scratch); 6230257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(scratch); 6231257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6232257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If names of slots in range from 1 to kProbes - 1 for the hash value are 6233257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // not equal to the name and kProbes-th slot is not used (its name is the 6234257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // undefined value), it guarantees the hash table doesn't contain the 6235257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // property. It's true even if some slots represent deleted properties 6236257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // (their names are the null value). 6237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = kInlinedProbes; i < kTotalProbes; i++) { 6238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 6239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, Operand(esp, 2 * kPointerSize)); 6240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i > 0) { 6241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(Operand(scratch), 6242257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Immediate(StringDictionary::GetProbeOffset(i))); 6243257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6244257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(scratch, Operand(esp, 0)); 6245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the entry size. 6247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 6248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. 6249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Having undefined at this place means the name is not contained. 6251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT_EQ(kSmiTagSize, 1); 6252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, Operand(dictionary_, 6253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch index_, 6254257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch times_pointer_size, 6255257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kElementsStartOffset - kHeapObjectTag)); 6256257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(scratch, masm->isolate()->factory()->undefined_value()); 6257257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, ¬_in_dictionary); 6258257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6259257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Stop if found the property. 6260257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(scratch, Operand(esp, 3 * kPointerSize)); 6261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &in_dictionary); 6262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6263257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { 6264257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If we hit a non symbol key during negative lookup 6265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // we have to bailout as this key might be equal to the 6266257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // key we are looking for. 6267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6268257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the entry name is not a symbol. 6269257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); 6270257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset), 6271257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kIsSymbolMask); 6272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &maybe_in_dictionary); 6273257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6275257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&maybe_in_dictionary); 6277257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If we are doing negative lookup then probing failure should be 6278257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // treated as a lookup success. For positive lookup probing failure 6279257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // should be treated as lookup failure. 6280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (mode_ == POSITIVE_LOOKUP) { 6281257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(result_, Immediate(0)); 6282257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Drop(1); 6283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 6284257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6285257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6286257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&in_dictionary); 6287257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(result_, Immediate(1)); 6288257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Drop(1); 6289257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 6290257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6291257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(¬_in_dictionary); 6292257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(result_, Immediate(0)); 6293257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Drop(1); 6294257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 6295257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6296257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6297257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 629880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#undef __ 629980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 630080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} } // namespace v8::internal 630180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 630280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif // V8_TARGET_ARCH_IA32 6303