code-stubs-ia32.cc revision 692be65d6b06edd9ff4cfc4c308555b7c99c1191
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 23969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch// The stub expects its argument on the stack and returns its result in tos_: 24069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch// zero for false, and a non-zero value for true. 24180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ToBooleanStub::Generate(MacroAssembler* masm) { 24269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label patch; 243257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Factory* factory = masm->isolate()->factory(); 24469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch const Register argument = eax; 2453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const Register map = edx; 2463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 24769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!types_.IsEmpty()) { 24869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(argument, Operand(esp, 1 * kPointerSize)); 24969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // undefined -> false 25269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false); 253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 254257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Boolean -> its value 25569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false); 25669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true); 25780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 'null' -> false. 25969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false); 26080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 26169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(SMI)) { 26269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Smis: 0 -> false, all other -> true 26369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_smi; 26469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfNotSmi(argument, ¬_smi, Label::kNear); 26569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // argument contains the correct return value already. 26669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!tos_.is(argument)) { 26769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(tos_, argument); 26869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 26969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 27069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_smi); 27169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } else if (types_.NeedsMap()) { 27269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If we need a map later and have a Smi -> patch. 27369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfSmi(argument, &patch, Label::kNear); 27469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 27580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 27669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.NeedsMap()) { 27769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(map, FieldOperand(argument, HeapObject::kMapOffset)); 27869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 27969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.CanBeUndetectable()) { 28069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ test_b(FieldOperand(map, Map::kBitFieldOffset), 28169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 1 << Map::kIsUndetectable); 28269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Undetectable -> false. 28369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_undetectable; 28469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, ¬_undetectable, Label::kNear); 28569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, Immediate(0)); 28669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 28769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_undetectable); 28869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 28969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 29080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 29169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(SPEC_OBJECT)) { 29269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // spec object -> true. 29369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_js_object; 29469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); 29569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(below, ¬_js_object, Label::kNear); 29669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // argument contains the correct return value already. 29769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!tos_.is(argument)) { 29869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, Immediate(1)); 29969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 30069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 30169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_js_object); 30269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 30380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 30469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(STRING)) { 30569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // String value -> false iff empty. 30669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_string; 30769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); 30869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(above_equal, ¬_string, Label::kNear); 30969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(tos_, FieldOperand(argument, String::kLengthOffset)); 31069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); // the string length is OK as the return value 31169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_string); 31269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 31380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 31469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(HEAP_NUMBER)) { 31569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // heap number -> false iff +0, -0, or NaN. 31669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_heap_number, false_result; 31769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(map, factory->heap_number_map()); 31869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_equal, ¬_heap_number, Label::kNear); 31969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ fldz(); 32069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ fld_d(FieldOperand(argument, HeapNumber::kValueOffset)); 32169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ FCmp(); 32269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &false_result, Label::kNear); 32369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // argument contains the correct return value already. 32469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!tos_.is(argument)) { 32569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, Immediate(1)); 32669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 32769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 32869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&false_result); 32969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, Immediate(0)); 33069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 33169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_heap_number); 33269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 33369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 33469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&patch); 33569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch GenerateTypeTransition(masm); 33669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch} 33769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 33869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 33969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid ToBooleanStub::CheckOddball(MacroAssembler* masm, 34069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Type type, 34169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Heap::RootListIndex value, 34269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch bool result) { 34369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch const Register argument = eax; 34469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(type)) { 34569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If we see an expected oddball, return its ToBoolean value tos_. 34669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label different_value; 34769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ CompareRoot(argument, value); 34869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_equal, &different_value, Label::kNear); 34969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!result) { 35069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If we have to return zero, there is no way around clearing tos_. 35169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, Immediate(0)); 35269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } else if (!tos_.is(argument)) { 35369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If we have to return non-zero, we can re-use the argument if it is the 35469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // same register as the result, because we never see Smi-zero here. 35569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, Immediate(1)); 35669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 35769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 35869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&different_value); 35969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 36069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch} 36169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 36269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 36369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) { 36469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ pop(ecx); // Get return address, operand is now on top of stack. 36569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ push(Immediate(Smi::FromInt(tos_.code()))); 36669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ push(Immediate(Smi::FromInt(types_.ToByte()))); 36769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ push(ecx); // Push return address. 36869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Patch the caller to an appropriate specialized stub and return the 36969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // operation result to the caller of the stub. 37069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ TailCallExternalReference( 37169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()), 37269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 3, 37369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 1); 37480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 37580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 37680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3778b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochclass FloatingPointHelper : public AllStatic { 3788b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch public: 3798b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch enum ArgLocation { 3808b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch ARGS_ON_STACK, 3818b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch ARGS_IN_REGISTERS 3828b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch }; 38380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3848b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Code pattern for loading a floating point value. Input value must 3858b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // be either a smi or a heap number object (fp value). Requirements: 3868b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operand in register number. Returns operand as floating point number 3878b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // on FPU stack. 3888b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadFloatOperand(MacroAssembler* masm, Register number); 38980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3908b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Code pattern for loading floating point values. Input values must 3918b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // be either smi or heap number objects (fp values). Requirements: 3928b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax. 3938b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Returns operands as floating point numbers on FPU stack. 3948b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadFloatOperands(MacroAssembler* masm, 3958b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register scratch, 3968b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch ArgLocation arg_location = ARGS_ON_STACK); 39780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3988b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Similar to LoadFloatOperand but assumes that both operands are smis. 3998b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Expects operands in edx, eax. 4008b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadFloatSmis(MacroAssembler* masm, Register scratch); 401b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4028b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Test if operands are smi or number objects (fp). Requirements: 4038b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operand_1 in eax, operand_2 in edx; falls through on float 4048b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operands, jumps to the non_float label otherwise. 4058b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void CheckFloatOperands(MacroAssembler* masm, 4068b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* non_float, 4078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register scratch); 408b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4098b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Checks that the two floating point numbers on top of the FPU stack 4108b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // have int32 values. 4118b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void CheckFloatOperandsAreInt32(MacroAssembler* masm, 4128b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* non_int32); 413b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4148b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Takes the operands in edx and eax and loads them as integers in eax 4158b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // and ecx. 4168b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadUnknownsAsIntegers(MacroAssembler* masm, 4178b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch bool use_sse3, 4188b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* operand_conversion_failure); 419b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4208b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Must only be called after LoadUnknownsAsIntegers. Assumes that the 4218b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operands are pushed on the stack, and that their conversions to int32 4228b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // are in eax and ecx. Checks that the original numbers were in the int32 4238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // range. 4248b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void CheckLoadedIntegersWereInt32(MacroAssembler* masm, 4258b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch bool use_sse3, 4268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* not_int32); 427b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4288b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Assumes that operands are smis or heap numbers and loads them 4298b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // into xmm0 and xmm1. Operands are in edx and eax. 4308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Leaves operands unchanged. 4318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadSSE2Operands(MacroAssembler* masm); 432b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Test if operands are numbers (smi or HeapNumber objects), and load 4348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // them into xmm0 and xmm1 if they are. Jump to label not_numbers if 4358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // either operand is not a number. Operands are in edx and eax. 4368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Leaves operands unchanged. 4378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers); 438b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4398b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Similar to LoadSSE2Operands but assumes that both operands are smis. 4408b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Expects operands in edx, eax. 4418b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadSSE2Smis(MacroAssembler* masm, Register scratch); 442b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Checks that the two floating point numbers loaded into xmm0 and xmm1 444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // have int32 values. 445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch static void CheckSSE2OperandsAreInt32(MacroAssembler* masm, 446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* non_int32, 447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch); 448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}; 449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Get the integer part of a heap number. Surprisingly, all this bit twiddling 452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// is faster than using the built-in instructions on floating point registers. 453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the 454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// trashed registers. 455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void IntegerConvert(MacroAssembler* masm, 456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register source, 457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch bool use_sse3, 458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* conversion_failure) { 459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); 460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done, right_exponent, normal_exponent; 461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch = ebx; 462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch2 = edi; 463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get exponent word. 464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); 465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get exponent alone in scratch2. 466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch2, scratch); 467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(scratch2, HeapNumber::kExponentMask); 468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (use_sse3) { 469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CpuFeatures::Scope scope(SSE3); 470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check whether the exponent is too big for a 64 bit signed integer. 471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch static const uint32_t kTooBigExponent = 472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; 473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(Operand(scratch2), Immediate(kTooBigExponent)); 474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(greater_equal, conversion_failure); 475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Load x87 register with heap number. 476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); 477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Reserve space for 64 bit answer. 478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sub(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. 479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Do conversion, which cannot fail because we checked the exponent. 480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fisttp_d(Operand(esp, 0)); 481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, Operand(esp, 0)); // Load low word of answer into ecx. 482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. 483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Load ecx with zero. We use this either for the final shift or 485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // for the answer. 486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xor_(ecx, Operand(ecx)); 487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check whether the exponent matches a 32 bit signed int that cannot be 488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // represented by a Smi. A non-smi 32 bit integer is 1.xxx * 2^30 so the 489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // exponent is 30 (biased). This is the exponent that we are fastest at and 490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // also the highest exponent we can handle here. 491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const uint32_t non_smi_exponent = 492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; 493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(Operand(scratch2), Immediate(non_smi_exponent)); 494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If we have a match of the int32-but-not-Smi exponent then skip some 495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // logic. 49669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(equal, &right_exponent, Label::kNear); 497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If the exponent is higher than that then go to slow case. This catches 498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // numbers that don't fit in a signed int32, infinities and NaNs. 49969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(less, &normal_exponent, Label::kNear); 500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch { 502257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle a big exponent. The only reason we have this code is that the 503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // >>> operator has a tendency to generate numbers with an exponent of 31. 504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const uint32_t big_non_smi_exponent = 505257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift; 506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(Operand(scratch2), Immediate(big_non_smi_exponent)); 507257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, conversion_failure); 508257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We have the big exponent, typically from >>>. This means the number is 509257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // in the range 2^31 to 2^32 - 1. Get the top bits of the mantissa. 510257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch2, scratch); 511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(scratch2, HeapNumber::kMantissaMask); 512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Put back the implicit 1. 513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ or_(scratch2, 1 << HeapNumber::kExponentShift); 514257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Shift up the mantissa bits to take up the space the exponent used to 515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // take. We just orred in the implicit bit so that took care of one and 516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // we want to use the full unsigned range so we subtract 1 bit from the 517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // shift distance. 518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1; 519257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shl(scratch2, big_shift_distance); 520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get the second half of the double. 521257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset)); 522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Shift down 21 bits to get the most significant 11 bits or the low 523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // mantissa word. 524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(ecx, 32 - big_shift_distance); 525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ or_(ecx, Operand(scratch2)); 526257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We have the answer in ecx, but we may need to negate it. 527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(scratch, Operand(scratch)); 52869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(positive, &done, Label::kNear); 529257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ neg(ecx); 53069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&done, Label::kNear); 531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 532257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 533257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&normal_exponent); 534257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Exponent word in scratch, exponent part of exponent word in scratch2. 535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Zero in ecx. 536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We know the exponent is smaller than 30 (biased). If it is less than 537257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie 538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // it rounds to zero. 539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const uint32_t zero_exponent = 540257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift; 541257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sub(Operand(scratch2), Immediate(zero_exponent)); 542257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // ecx already has a Smi zero. 54369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(less, &done, Label::kNear); 544257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 545257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We have a shifted exponent between 0 and 30 in scratch2. 546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(scratch2, HeapNumber::kExponentShift); 547257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, Immediate(30)); 548257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sub(ecx, Operand(scratch2)); 549257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 550257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&right_exponent); 551257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Here ecx is the shift, scratch is the exponent word. 552257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get the top bits of the mantissa. 553257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(scratch, HeapNumber::kMantissaMask); 554257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Put back the implicit 1. 555257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ or_(scratch, 1 << HeapNumber::kExponentShift); 556257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Shift up the mantissa bits to take up the space the exponent used to 557257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // take. We have kExponentShift + 1 significant bits int he low end of the 558257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // word. Shift them to the top bits. 559257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2; 560257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shl(scratch, shift_distance); 561257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get the second half of the double. For some exponents we don't 562257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // actually need this because the bits get shifted out again, but 563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // it's probably slower to test than just to do it. 564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset)); 565257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Shift down 22 bits to get the most significant 10 bits or the low 566257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // mantissa word. 567257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(scratch2, 32 - shift_distance); 568257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ or_(scratch2, Operand(scratch)); 569257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Move down according to the exponent. 570257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr_cl(scratch2); 571257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Now the unsigned answer is in scratch2. We need to move it to ecx and 572257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // we may need to fix the sign. 573257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label negative; 574257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xor_(ecx, Operand(ecx)); 575257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset)); 576257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(greater, &negative, Label::kNear); 577257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, scratch2); 578257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 579257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&negative); 580257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sub(ecx, Operand(scratch2)); 581257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&done); 582257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 583257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 584257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 585257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid UnaryOpStub::PrintName(StringStream* stream) { 587257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const char* op_name = Token::Name(op_); 588257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const char* overwrite_name = NULL; // Make g++ happy. 589257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (mode_) { 590257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; 591257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; 592257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 5933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("UnaryOpStub_%s_%s_%s", 5943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch op_name, 5953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch overwrite_name, 5963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch UnaryOpIC::GetName(operand_type_)); 597257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 598257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 599257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 600257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::Generate(MacroAssembler* masm) { 602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (operand_type_) { 603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::UNINITIALIZED: 604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 606257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::SMI: 607257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStub(masm); 608257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 609257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::HEAP_NUMBER: 610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStub(masm); 611257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::GENERIC: 613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStub(masm); 614257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 616257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 618257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(ecx); // Save return address. 6213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 6223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(eax); // the operand 623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(Immediate(Smi::FromInt(op_))); 6243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(Immediate(Smi::FromInt(mode_))); 625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(Immediate(Smi::FromInt(operand_type_))); 626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 627257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(ecx); // Push return address. 628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Patch the caller to an appropriate specialized stub and return the 630257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // operation result to the caller of the stub. 631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ TailCallExternalReference( 6323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1); 633257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStubSub(masm); 641257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 642257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 643257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStubBitNot(masm); 644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 646257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 647257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 650257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 651257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) { 652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, undo, slow; 653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, 654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::kNear, Label::kNear, Label::kNear); 655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&undo); 656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeUndo(masm); 657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) { 664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi; 665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi); 666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, 672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* non_smi, 673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* undo, 674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* slow, 675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance non_smi_near, 676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance undo_near, 677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance slow_near) { 678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check whether the value is a smi. 6793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, non_smi, non_smi_near); 680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We can't handle -0 with smis, so use a type transition for that case. 682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(eax, Operand(eax)); 683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, slow, slow_near); 684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Try optimistic subtraction '0 - value', saving operand in eax for undo. 686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edx, Operand(eax)); 687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(0)); 688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sub(eax, Operand(edx)); 689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(overflow, undo, undo_near); 690257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 691257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeBitNot( 695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* non_smi, 697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance non_smi_near) { 698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check whether the value is a smi. 6993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, non_smi, non_smi_near); 700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Flip bits and revert inverted smi-tag. 702257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ not_(eax); 703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(eax, ~kSmiTagMask); 704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) { 709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(eax, Operand(edx)); 710257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 711257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 712257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 713257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 714257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 715257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 716257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStubSub(masm); 718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStubBitNot(masm); 721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 727257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 728257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) { 729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, undo, slow, call_builtin; 730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &non_smi, &undo, &call_builtin, Label::kNear); 731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeSub(masm, &slow); 733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&undo); 734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeUndo(masm); 735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_builtin); 738257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 739257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 740257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 741257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 742257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubBitNot( 743257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm) { 744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow; 745257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); 746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 747257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeBitNot(masm, &slow); 748257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 749257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 750257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 751257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 752257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, 754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* slow) { 755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); 756257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(edx, masm->isolate()->factory()->heap_number_map()); 757257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, slow); 758257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 759257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (mode_ == UNARY_OVERWRITE) { 760257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset), 761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Immediate(HeapNumber::kSignMask)); // Flip sign. 762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 763257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edx, Operand(eax)); 764257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // edx: operand 765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label slow_allocate_heapnumber, heapnumber_allocated; 767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber); 76869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&heapnumber_allocated, Label::kNear); 769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 770257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow_allocate_heapnumber); 771257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ EnterInternalFrame(); 772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(edx); 773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallRuntime(Runtime::kNumberAlloc, 0); 774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(edx); 775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ LeaveInternalFrame(); 776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&heapnumber_allocated); 778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // eax: allocated 'empty' number 779257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); 780257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xor_(ecx, HeapNumber::kSignMask); // Flip sign. 781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx); 782257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset)); 783257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); 784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 785257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 787257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 789257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm, 790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* slow) { 791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); 792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(edx, masm->isolate()->factory()->heap_number_map()); 793257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, slow); 794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 795257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Convert the heap number in eax to an untagged integer in ecx. 796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), slow); 797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Do the bitwise operation and check if the result fits in a smi. 799257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label try_float; 800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ not_(ecx); 801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(ecx, 0xc0000000); 802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(sign, &try_float, Label::kNear); 803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Tag the result as a smi and we're done. 805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTagSize == 1); 806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(eax, Operand(ecx, times_2, kSmiTag)); 807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 808257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 809257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Try to store the result in a heap number. 810257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&try_float); 811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (mode_ == UNARY_NO_OVERWRITE) { 812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label slow_allocate_heapnumber, heapnumber_allocated; 813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ebx, eax); 814257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ AllocateHeapNumber(eax, edx, edi, &slow_allocate_heapnumber); 815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&heapnumber_allocated); 816257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 817257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow_allocate_heapnumber); 818257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ EnterInternalFrame(); 819257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Push the original HeapNumber on the stack. The integer value can't 820257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // be stored since it's untagged and not in the smi range (so we can't 821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // smi-tag it). We'll recalculate the value after the GC instead. 822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(ebx); 823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallRuntime(Runtime::kNumberAlloc, 0); 824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // New HeapNumber is in eax. 825257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(edx); 826257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ LeaveInternalFrame(); 827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // IntegerConvert uses ebx and edi as scratch registers. 828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // This conversion won't go slow-case. 829257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch IntegerConvert(masm, edx, CpuFeatures::IsSupported(SSE3), slow); 830257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ not_(ecx); 831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 832257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&heapnumber_allocated); 833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 834257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 835257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 836257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cvtsi2sd(xmm0, Operand(ecx)); 837257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 839257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(ecx); 840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fild_s(Operand(esp, 0)); 841257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(ecx); 842257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 843257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 844257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 845257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 846257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 847257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 848257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 849257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) { 850257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 852257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStubSub(masm); 853257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStubBitNot(masm); 856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 858257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 860257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 861257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 862257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 863257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) { 864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, undo, slow; 865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, Label::kNear); 866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeSub(masm, &slow); 868257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&undo); 869257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeUndo(masm); 870257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 871257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 873257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) { 876257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow; 877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); 878257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 879257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeBitNot(masm, &slow); 880257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 881257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 882257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 883257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 884257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) { 886257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle the slow case by jumping to the corresponding JavaScript builtin. 887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(ecx); // pop return address. 888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(eax); 889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(ecx); // push return address 890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION); 893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); 896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 898257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 901b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 902b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 904b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(ecx); // Save return address. 905b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(edx); 906b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(eax); 907b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Left and right arguments are now on top. 908b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Push this stub's key. Although the operation and the type info are 909b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // encoded into the key, the encoding is opaque, so push them too. 910b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(MinorKey()))); 911b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(op_))); 912b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(operands_type_))); 913b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 914b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(ecx); // Push return address. 915b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 916b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Patch the caller to an appropriate specialized stub and return the 917b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // operation result to the caller of the stub. 918b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TailCallExternalReference( 919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ExternalReference(IC_Utility(IC::kBinaryOp_Patch), 92044f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()), 921b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5, 922b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1); 923b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 924b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 925b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 926b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// Prepare for a type transition runtime call when the args are already on 927b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// the stack, under the return address. 928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) { 929b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(ecx); // Save return address. 930b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Left and right arguments are already on top of the stack. 931b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Push this stub's key. Although the operation and the type info are 932b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // encoded into the key, the encoding is opaque, so push them too. 933b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(MinorKey()))); 934b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(op_))); 935b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(operands_type_))); 936b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 937b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(ecx); // Push return address. 938b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 939b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Patch the caller to an appropriate specialized stub and return the 940b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // operation result to the caller of the stub. 941b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TailCallExternalReference( 942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ExternalReference(IC_Utility(IC::kBinaryOp_Patch), 94344f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()), 944b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5, 945b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1); 946b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 947b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 948b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::Generate(MacroAssembler* masm) { 950b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (operands_type_) { 951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::UNINITIALIZED: 952b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 953b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::SMI: 955b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateSmiStub(masm); 956b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::INT32: 958b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateInt32Stub(masm); 959b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 960257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::HEAP_NUMBER: 961b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapNumberStub(masm); 962b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::ODDBALL: 96444f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateOddballStub(masm); 96544f0eee88ff00398ff7f715fab053374d808c90dSteve Block break; 966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::BOTH_STRING: 967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateBothStringStub(masm); 968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 969257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::STRING: 970b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateStringStub(masm); 971b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::GENERIC: 973b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateGeneric(masm); 974b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 975b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 976b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 977b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 978b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 979b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 980b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 9813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid BinaryOpStub::PrintName(StringStream* stream) { 982b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const char* op_name = Token::Name(op_); 983b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const char* overwrite_name; 984b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode_) { 985b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: overwrite_name = "Alloc"; break; 986b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; 987b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; 988b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: overwrite_name = "UnknownOverwrite"; break; 989b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 9903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("BinaryOpStub_%s_%s_%s", 9913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch op_name, 9923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch overwrite_name, 9933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch BinaryOpIC::GetName(operands_type_)); 994b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 995b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 996b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiCode( 998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 999b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* slow, 1000b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { 1001b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 1. Move arguments into edx, eax except for DIV and MOD, which need the 1002b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // dividend in eax and edx free for the division. Use eax, ebx for those. 1003b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment load_comment(masm, "-- Load arguments"); 1004b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register left = edx; 1005b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register right = eax; 1006b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ == Token::DIV || op_ == Token::MOD) { 1007b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch left = eax; 1008b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch right = ebx; 1009b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, eax); 1010b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, edx); 1011b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1012b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1013b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1014b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 2. Prepare the smi check of both operands by oring them together. 1015b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment smi_check_comment(masm, "-- Smi check arguments"); 1016b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_smis; 1017b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register combined = ecx; 1018b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(!left.is(combined) && !right.is(combined)); 1019b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1020b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1021b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Perform the operation into eax and smi check the result. Preserve 1022b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax in case the result is not a smi. 1023b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(!left.is(ecx) && !right.is(ecx)); 1024b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, right); 1025b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ or_(right, Operand(left)); // Bitwise or is commutative. 1026b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch combined = right; 1027b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1028b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1029b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1030b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1031b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1032b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1033b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1034b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1035b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1036b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(combined, right); 1037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ or_(combined, Operand(left)); 1038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1039b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1042b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Move the right operand into ecx for the shift operation, use eax 1044b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // for the smi check register. 1045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(!left.is(ecx) && !right.is(ecx)); 1046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, right); 1047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ or_(right, Operand(left)); 1048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch combined = right; 1049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1053b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 3. Perform the smi check of the operands. 1056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTag == 0); // Adjust zero check if not the case. 10573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(combined, ¬_smis); 1058b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 4. Operands are both smis, perform the operation leaving the result in 1060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax and check the result if necessary. 1061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment perform_smi(masm, "-- Perform smi operation"); 1062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label use_fp_on_smis; 1063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Nothing to do. 1066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(right.is(eax)); 1070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ xor_(right, Operand(left)); // Bitwise xor is commutative. 1071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(right.is(eax)); 1075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ and_(right, Operand(left)); // Bitwise and is commutative. 1076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1077b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1078b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1079b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Remove tags from operands (but keep sign). 1080b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(left); 1081b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(ecx); 1082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Perform the operation. 1083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ shl_cl(left); 1084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check that the *signed* result fits in a smi. 1085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(left, 0xc0000000); 1086257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(sign, &use_fp_on_smis); 1087b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag the result and store it in register eax. 1088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(left); 1089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, left); 1090b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1091b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Remove tags from operands (but keep sign). 1094b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(left); 1095b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(ecx); 1096b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Perform the operation. 1097b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sar_cl(left); 1098b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag the result and store it in register eax. 1099b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(left); 1100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, left); 1101b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1102b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1104b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Remove tags from operands (but keep sign). 1105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(left); 1106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(ecx); 1107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Perform the operation. 1108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ shr_cl(left); 1109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check that the *unsigned* result fits in a smi. 1110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Neither of the two high-order bits can be set: 1111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // - 0x80000000: high bit would be lost when smi tagging. 1112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // - 0x40000000: this number would convert to negative when 1113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Smi tagging these two cases can only happen with shifts 1114b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // by 0 or 1 when handed a valid smi. 1115b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(left, Immediate(0xc0000000)); 1116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &use_fp_on_smis); 1117b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag the result and store it in register eax. 1118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(left); 1119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, left); 1120b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(right.is(eax)); 1124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(right, Operand(left)); // Addition is commutative. 1125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(overflow, &use_fp_on_smis); 1126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(left, Operand(right)); 1130257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(overflow, &use_fp_on_smis); 1131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, left); 1132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the smi tag is 0 we can just leave the tag on one operand. 1136b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTag == 0); // Adjust code below if not the case. 1137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // We can't revert the multiplication if the result is not a smi 1138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // so save the right operand. 1139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, right); 1140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Remove tag from one of the operands (but keep sign). 1141b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(right); 1142b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Do multiplication. 1143b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ imul(right, Operand(left)); // Multiplication is commutative. 1144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(overflow, &use_fp_on_smis); 1145b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for negative zero result. Use combined = left | right. 1146b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ NegativeZeroTest(right, combined, &use_fp_on_smis); 1147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1148b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1149b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1150b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // We can't revert the division if the result is not a smi so 1151b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // save the left operand. 1152b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edi, left); 1153b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for 0 divisor. 1154b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(right, Operand(right)); 1155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &use_fp_on_smis); 1156b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Sign extend left into edx:eax. 1157b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(left.is(eax)); 1158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cdq(); 1159b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Divide edx:eax by right. 1160b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ idiv(right); 1161b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for the corner case of dividing the most negative smi by 1162b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // -1. We cannot use the overflow flag, since it is not set by idiv 1163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // instruction. 1164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); 1165b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(eax, 0x40000000); 1166b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(equal, &use_fp_on_smis); 1167b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for negative zero result. Use combined = left | right. 1168b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ NegativeZeroTest(eax, combined, &use_fp_on_smis); 1169b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check that the remainder is zero. 1170b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(edx, Operand(edx)); 1171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &use_fp_on_smis); 1172b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag the result and store it in register eax. 1173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(eax); 1174b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1175b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1176b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1177b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for 0 divisor. 1178b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(right, Operand(right)); 1179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, ¬_smis); 1180b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1181b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Sign extend left into edx:eax. 1182b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(left.is(eax)); 1183b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cdq(); 1184b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Divide edx:eax by right. 1185b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ idiv(right); 1186b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for negative zero result. Use combined = left | right. 1187b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ NegativeZeroTest(edx, combined, slow); 1188b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Move remainder to register eax. 1189b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, edx); 1190b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1191b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1192b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1193b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1194b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1195b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1196b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 5. Emit return of result in eax. Some operations have registers pushed. 1197b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1198b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1200b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1202b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1203b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1204b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1205b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1207b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1208b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1209b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1210b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1211b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); 1212b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1213b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1214b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1215b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1216b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1217b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 6. For some operations emit inline code to perform floating point 1218b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // operations on known smis (e.g., if the result of the operation 1219b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // overflowed the smi range). 1220b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (allow_heapnumber_results == NO_HEAPNUMBER_RESULTS) { 1221b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&use_fp_on_smis); 1222b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Undo the effects of some operations, and some register moves. 1224b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1225b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // The arguments are saved on the stack, and only used from there. 1226b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1227b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1228b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Revert right = right + left. 1229b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(right, Operand(left)); 1230b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1231b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1232b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Revert left = left - right. 1233b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(left, Operand(right)); 1234b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1235b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1236b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Right was clobbered but a copy is in ebx. 1237b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(right, ebx); 1238b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1239b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1240b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Left was clobbered but a copy is in edi. Right is in ebx for 1241b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // division. They should be in eax, ebx for jump to not_smi. 1242b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, edi); 1243b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1244b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1245b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // No other operators jump to use_fp_on_smis. 1246b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1247b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1248b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(¬_smis); 1249b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1250b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS); 1251b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SHL: 1253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SHR: { 1254b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment perform_float(masm, "-- Perform float operation on smis"); 1255b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&use_fp_on_smis); 1256b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Result we want is in left == edx, so we can put the allocated heap 1257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // number in eax. 1258b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, ecx, ebx, slow); 1259b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Store the result in the HeapNumber and return. 1260257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // It's OK to overwrite the arguments on the stack because we 1261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // are about to return. 1262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (op_ == Token::SHR) { 1263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), left); 1264257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(Operand(esp, 2 * kPointerSize), Immediate(0)); 1265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fild_d(Operand(esp, 1 * kPointerSize)); 1266b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 1268257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT_EQ(Token::SHL, op_); 1269257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1270257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1271257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cvtsi2sd(xmm0, Operand(left)); 1272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1273257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 1274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), left); 1275257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fild_s(Operand(esp, 1 * kPointerSize)); 1276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1277257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 1278b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1279257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 1280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 1281b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1282b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: { 1287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment perform_float(masm, "-- Perform float operation on smis"); 1288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&use_fp_on_smis); 1289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Restore arguments to edx, eax. 1290b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1291b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1292b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Revert right = right + left. 1293b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(right, Operand(left)); 1294b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1295b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Revert left = left - right. 1297b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(left, Operand(right)); 1298b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1299b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1300b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Right was clobbered but a copy is in ebx. 1301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(right, ebx); 1302b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Left was clobbered but a copy is in edi. Right is in ebx for 1305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // division. 1306b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, edi); 1307b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, right); 1308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1309b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1310b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1311b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1312b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(ecx, ebx, no_reg, slow); 13138b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1314b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1315b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Smis(masm, ebx); 1316b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1317b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ addsd(xmm0, xmm1); break; 1318b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ subsd(xmm0, xmm1); break; 1319b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ mulsd(xmm0, xmm1); break; 1320b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ divsd(xmm0, xmm1); break; 1321b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1322b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1323b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0); 1324b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // SSE2 not available, use FPU. 1325b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadFloatSmis(masm, ebx); 1326b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1327b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ faddp(1); break; 1328b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ fsubp(1); break; 1329b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ fmulp(1); break; 1330b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ fdivp(1); break; 1331b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1332b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1333b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset)); 1334b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1335b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, ecx); 1336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1337b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1338b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1339b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1340b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1341b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1342b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1343b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1344b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1345b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 7. Non-smi operands, fall out to the non-smi code with the operands in 1346b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // edx and eax. 1347b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment done_comment(masm, "-- Enter non-smi code"); 1348b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_smis); 1349b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1350b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1351b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1352b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1353b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1354b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Right operand is saved in ecx and eax was destroyed by the smi 1355b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // check. 1356b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, ecx); 1357b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1358b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1359b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1361b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Operands are in eax, ebx at this point. 1362b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, eax); 1363b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, ebx); 1364b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1365b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1366b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1367b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1368b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1369b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1370b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1371b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 1373b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label call_runtime; 1374b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1375b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1376b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1377b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1378b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1379b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1380b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1381b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1382b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1383b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1384b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1385b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1386b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1387b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1388b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1389b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1390b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1391b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1392b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1393b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (result_type_ == BinaryOpIC::UNINITIALIZED || 1395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch result_type_ == BinaryOpIC::SMI) { 1396b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateSmiCode(masm, &call_runtime, NO_HEAPNUMBER_RESULTS); 1397b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1398b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 1399b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1400b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&call_runtime); 1401b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1402b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1403b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1404b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1405b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1406b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 1407b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1408b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1409b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1410b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1411b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1412b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1413b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1414b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1415b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransitionWithSavedArgs(masm); 1416b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1417b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1418b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1419b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1420b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1421b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1422b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { 1424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(operands_type_ == BinaryOpIC::STRING); 1425b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(op_ == Token::ADD); 14261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Try to add arguments as strings, otherwise, transition to the generic 1427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // BinaryOpIC type. 14281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateAddStrings(masm); 1429b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 1430b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1431b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1432b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { 1434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label call_runtime; 1435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); 1436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(op_ == Token::ADD); 1437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If both arguments are strings, call the string add stub. 1438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Otherwise, do a transition. 1439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 1441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = edx; 1442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = eax; 1443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Test if left operand is a string. 144569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfSmi(left, &call_runtime, Label::kNear); 1446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); 144769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(above_equal, &call_runtime, Label::kNear); 1448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Test if right operand is a string. 145069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfSmi(right, &call_runtime, Label::kNear); 1451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); 145269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(above_equal, &call_runtime, Label::kNear); 1453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); 1455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateRegisterArgsPush(masm); 1456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ TailCallStub(&string_add_stub); 1457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_runtime); 1459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 1460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { 1464b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label call_runtime; 1465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(operands_type_ == BinaryOpIC::INT32); 1466b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1467b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Floating point case. 1468b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1469b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1470b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1471b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1472b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: { 1473b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 1474b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_int32; 14758b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1476b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1477b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 1478b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); 1479b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1480b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ addsd(xmm0, xmm1); break; 1481b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ subsd(xmm0, xmm1); break; 1482b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ mulsd(xmm0, xmm1); break; 1483b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ divsd(xmm0, xmm1); break; 1484b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1485b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1486b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check result type if it is currently Int32. 1487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (result_type_ <= BinaryOpIC::INT32) { 1488b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvttsd2si(ecx, Operand(xmm0)); 1489b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm2, Operand(ecx)); 1490b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm0, xmm2); 1491b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, ¬_int32); 1492b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(carry, ¬_int32); 1493b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1494b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &call_runtime); 1495b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1496b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1497b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // SSE2 not available, use FPU. 1498b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); 1499b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadFloatOperands( 1500b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch masm, 1501b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ecx, 1502b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::ARGS_IN_REGISTERS); 1503b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckFloatOperandsAreInt32(masm, ¬_int32); 1504b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1505b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ faddp(1); break; 1506b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ fsubp(1); break; 1507b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ fmulp(1); break; 1508b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ fdivp(1); break; 1509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1511b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label after_alloc_failure; 1512b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &after_alloc_failure); 1513b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1514b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1515b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&after_alloc_failure); 1516b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ffree(); 1517b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&call_runtime); 1518b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1519b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1520b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 1521b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_int32); 1522b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 1523b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1524b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1525b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1526b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: { 1527b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // For MOD we go directly to runtime in the non-smi case. 1528b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1529b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1530b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1534b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: { 1536b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 1538b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_int32; 1539b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label non_smi_result; 1540b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch /* { 1541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 1543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); 1544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch }*/ 1545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadUnknownsAsIntegers(masm, 1546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch use_sse3_, 1547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ¬_floats); 1548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_, 1549b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ¬_int32); 1550b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; 1552b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; 1553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; 1554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: __ sar_cl(eax); break; 1555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: __ shl_cl(eax); break; 1556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: __ shr_cl(eax); break; 1557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ == Token::SHR) { 1560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result is non-negative and fits in a smi. 1561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(eax, Immediate(0xc0000000)); 1562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &call_runtime); 1563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result fits in a smi. 1565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(eax, 0xc0000000); 156669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(negative, &non_smi_result, Label::kNear); 1567b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag smi result and return. 1569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(eax); 1570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // All ops except SHR return a signed int32 that we load in 1573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // a HeapNumber. 1574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ != Token::SHR) { 1575b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&non_smi_result); 1576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number if needed. 1577b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, Operand(eax)); // ebx: result 1578257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label skip_allocation; 1579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode_) { 1580b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: 1581b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: 1582b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the operand was an object, we skip the 1583b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 1584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 1585b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1 * kPointerSize : 2 * kPointerSize)); 15863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 1587b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fall through! 1588b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: 1589b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 1590b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 1591b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1592b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1593b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1594b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Store the result in the HeapNumber and return. 15958b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1596b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1597b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm0, Operand(ebx)); 1598b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1599b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1600b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ebx); 1601b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fild_s(Operand(esp, 1 * kPointerSize)); 1602b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1603b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1604b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1605b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1606b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1607b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 1608b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_int32); 1609b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransitionWithSavedArgs(masm); 1610b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1611b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1612b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); break; 1613b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1614b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1615b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If an allocation fails, or SHR or MOD hit a hard case, 1616b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // use the runtime system to get the correct result. 1617b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&call_runtime); 1618b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1619b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1620b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1621b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1622b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 1623b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1624b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1625b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1626b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 1627b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1628b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1629b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1630b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 1631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1632b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1633b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 1635b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1636b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1637b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1638b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 1639b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1640b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1641b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 1642b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1643b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1644b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 1645b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1646b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1647b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 1648b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1649b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1650b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 1651b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1652b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1653b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 1654b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1655b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1656b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 1657b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1658b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1659b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1660b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1661b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1662b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1663b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { 166544f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (op_ == Token::ADD) { 166644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Handle string addition here, because it is the only operation 166744f0eee88ff00398ff7f715fab053374d808c90dSteve Block // that does not do a ToNumber conversion on the operands. 166844f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateAddStrings(masm); 166944f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 167044f0eee88ff00398ff7f715fab053374d808c90dSteve Block 1671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Factory* factory = masm->isolate()->factory(); 1672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 167344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Convert odd ball arguments to numbers. 1674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label check, done; 1675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(edx, factory->undefined_value()); 1676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &check, Label::kNear); 167744f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (Token::IsBitOp(op_)) { 167844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ xor_(edx, Operand(edx)); 167944f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 1680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edx, Immediate(factory->nan_value())); 168144f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 1682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 168344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&check); 1684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(eax, factory->undefined_value()); 1685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &done, Label::kNear); 168644f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (Token::IsBitOp(op_)) { 168744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ xor_(eax, Operand(eax)); 168844f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 1689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(eax, Immediate(factory->nan_value())); 169044f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 169144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&done); 169244f0eee88ff00398ff7f715fab053374d808c90dSteve Block 169344f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateHeapNumberStub(masm); 169444f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 169544f0eee88ff00398ff7f715fab053374d808c90dSteve Block 169644f0eee88ff00398ff7f715fab053374d808c90dSteve Block 1697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 1698b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label call_runtime; 1699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Floating point case. 1701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1704b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1705b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: { 1706b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 17078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1708b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 1710b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ addsd(xmm0, xmm1); break; 1713b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ subsd(xmm0, xmm1); break; 1714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ mulsd(xmm0, xmm1); break; 1715b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ divsd(xmm0, xmm1); break; 1716b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1717b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &call_runtime); 1719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1720b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1721b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // SSE2 not available, use FPU. 1722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); 1723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadFloatOperands( 1724b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch masm, 1725b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ecx, 1726b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::ARGS_IN_REGISTERS); 1727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1728b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ faddp(1); break; 1729b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ fsubp(1); break; 1730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ fmulp(1); break; 1731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ fdivp(1); break; 1732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1733b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1734b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label after_alloc_failure; 1735b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &after_alloc_failure); 1736b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1737b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1738b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&after_alloc_failure); 1739b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ffree(); 1740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&call_runtime); 1741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 1744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 1745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: { 1749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // For MOD we go directly to runtime in the non-smi case. 1750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1752b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1754b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1756b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1757b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: { 1758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1759b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 1760b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label non_smi_result; 1761b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadUnknownsAsIntegers(masm, 1762b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch use_sse3_, 1763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ¬_floats); 1764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1765b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; 1766b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; 1767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; 1768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: __ sar_cl(eax); break; 1769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: __ shl_cl(eax); break; 1770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: __ shr_cl(eax); break; 1771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1772b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1773b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ == Token::SHR) { 1774b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result is non-negative and fits in a smi. 1775b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(eax, Immediate(0xc0000000)); 1776b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &call_runtime); 1777b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1778b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result fits in a smi. 1779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(eax, 0xc0000000); 178069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(negative, &non_smi_result, Label::kNear); 1781b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag smi result and return. 1783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(eax); 1784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1785b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1786b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // All ops except SHR return a signed int32 that we load in 1787b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // a HeapNumber. 1788b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ != Token::SHR) { 1789b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&non_smi_result); 1790b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number if needed. 1791b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, Operand(eax)); // ebx: result 1792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label skip_allocation; 1793b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode_) { 1794b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: 1795b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: 1796b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the operand was an object, we skip the 1797b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 1798b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 1799b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1 * kPointerSize : 2 * kPointerSize)); 18003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 1801b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fall through! 1802b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: 1803b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 1804b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 1805b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1806b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1807b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1808b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Store the result in the HeapNumber and return. 18098b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1810b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1811b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm0, Operand(ebx)); 1812b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1813b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1814b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ebx); 1815b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fild_s(Operand(esp, 1 * kPointerSize)); 1816b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1817b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1818b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1819b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1820b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1821b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 1822b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransitionWithSavedArgs(masm); 1823b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1824b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1825b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); break; 1826b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1827b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1828b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If an allocation fails, or SHR or MOD hit a hard case, 1829b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // use the runtime system to get the correct result. 1830b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&call_runtime); 1831b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1832b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1833b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1834b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1835b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 1836b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1837b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1838b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1839b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 1840b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1843b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 1844b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1845b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1846b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1847b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 1848b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 1852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 1855b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1856b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1857b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 1858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1860b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 1861b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1862b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1863b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 1864b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1865b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1866b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 1867b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1868b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1869b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 1870b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1871b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1872b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1873b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1874b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1875b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1876b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { 1878b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label call_runtime; 1879b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 188044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 188144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->generic_binary_stub_calls(), 1); 1882b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1883b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1884b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1885b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1886b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1887b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1888b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1889b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1890b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1891b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1892b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1893b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1894b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1895b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1896b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1897b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1898b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1899b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1900b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1901b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1902b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 1903b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1904b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Floating point case. 1905b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1906b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1907b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1908b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1909b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: { 1910b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 19118b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1912b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1913b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 1914b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1915b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1916b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ addsd(xmm0, xmm1); break; 1917b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ subsd(xmm0, xmm1); break; 1918b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ mulsd(xmm0, xmm1); break; 1919b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ divsd(xmm0, xmm1); break; 1920b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1921b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1922b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &call_runtime); 1923b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1924b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1925b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // SSE2 not available, use FPU. 1926b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); 1927b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadFloatOperands( 1928b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch masm, 1929b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ecx, 1930b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::ARGS_IN_REGISTERS); 1931b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1932b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ faddp(1); break; 1933b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ fsubp(1); break; 1934b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ fmulp(1); break; 1935b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ fdivp(1); break; 1936b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1937b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1938b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label after_alloc_failure; 1939b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &after_alloc_failure); 1940b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1941b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1942b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&after_alloc_failure); 1943b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ffree(); 1944b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&call_runtime); 1945b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1946b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 1947b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1948b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1949b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: { 1950b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // For MOD we go directly to runtime in the non-smi case. 1951b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1952b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1953b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1954b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1955b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1956b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1957b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1958b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: { 1959b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label non_smi_result; 1960b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadUnknownsAsIntegers(masm, 1961b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch use_sse3_, 1962b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch &call_runtime); 1963b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1964b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; 1965b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; 1966b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; 1967b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: __ sar_cl(eax); break; 1968b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: __ shl_cl(eax); break; 1969b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: __ shr_cl(eax); break; 1970b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1971b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1972b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ == Token::SHR) { 1973b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result is non-negative and fits in a smi. 1974b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(eax, Immediate(0xc0000000)); 1975b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &call_runtime); 1976b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1977b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result fits in a smi. 1978b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(eax, 0xc0000000); 197969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(negative, &non_smi_result, Label::kNear); 1980b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1981b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag smi result and return. 1982b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(eax); 1983b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop the arguments from the stack. 1984b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1985b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // All ops except SHR return a signed int32 that we load in 1986b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // a HeapNumber. 1987b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ != Token::SHR) { 1988b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&non_smi_result); 1989b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number if needed. 1990b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, Operand(eax)); // ebx: result 1991257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label skip_allocation; 1992b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode_) { 1993b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: 1994b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: 1995b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the operand was an object, we skip the 1996b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 1997b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 1998b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1 * kPointerSize : 2 * kPointerSize)); 19993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 2000b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fall through! 2001b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: 2002b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 2003b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 2004b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2005b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 2006b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2007b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Store the result in the HeapNumber and return. 20088b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 2009b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 2010b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm0, Operand(ebx)); 2011b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 2012b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 2013b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ebx); 2014b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fild_s(Operand(esp, 1 * kPointerSize)); 2015b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2016b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2017b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); 2018b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2019b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2020b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2021b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); break; 2022b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2023b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2024b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If all else fails, use the runtime system to get the correct 2025b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // result. 2026b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&call_runtime); 2027b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 2028b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: { 20291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateAddStrings(masm); 2030b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 2031b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 2032b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2033b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2034b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 2035b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 2036b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 2037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 2039b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 2040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 2041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2042b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 2043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 2044b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 2045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 2047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 2048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 2050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 2051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 2053b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 2054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 2056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 2057b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2058b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 2059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 2060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 2062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 2063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 2065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 2066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 2068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 2069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { 2074e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ASSERT(op_ == Token::ADD); 2075257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label left_not_string, call_runtime; 20761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 20771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Registers containing left and right operands respectively. 20781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register left = edx; 20791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register right = eax; 20801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 20811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Test if left operand is a string. 20823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(left, &left_not_string, Label::kNear); 20831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); 2084257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &left_not_string, Label::kNear); 20851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 20861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); 20871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateRegisterArgsPush(masm); 20881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ TailCallStub(&string_add_left_stub); 20891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 20901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Left operand is not a string, test right. 20911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&left_not_string); 20923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(right, &call_runtime, Label::kNear); 20931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); 2094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &call_runtime, Label::kNear); 20951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 20961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); 20971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateRegisterArgsPush(masm); 20981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ TailCallStub(&string_add_right_stub); 20991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 21001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Neither argument is a string. 21011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&call_runtime); 21021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 21031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 21041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapResultAllocation( 2106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch MacroAssembler* masm, 2107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* alloc_failure) { 2108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label skip_allocation; 2109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch OverwriteMode mode = mode_; 2110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode) { 2111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: { 2112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the argument in edx is already an object, we skip the 2113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 21143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(edx, &skip_allocation, Label::kNear); 2115b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number for the result. Keep eax and edx intact 2116b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // for the possible runtime call. 2117b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); 2118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Now edx can be overwritten losing one of the arguments as we are 2119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // now done and will not need it any more. 2120b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, Operand(ebx)); 2121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 2122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Use object in edx as a result holder 2123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(edx)); 2124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: 2127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the argument in eax is already an object, we skip the 2128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 21293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 2130b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fall through! 2131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: 2132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number for the result. Keep eax and edx intact 2133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // for the possible runtime call. 2134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); 2135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Now eax can be overwritten losing one of the arguments as we are 2136b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // now done and will not need it any more. 2137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, ebx); 2138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 2139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 2141b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2142b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2143b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2144b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { 214680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ecx); 2147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(edx); 2148b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(eax); 214980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ecx); 215080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 215180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 215280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 215380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::Generate(MacroAssembler* masm) { 2154b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // TAGGED case: 2155b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input: 2156b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // esp[4]: tagged number input argument (should be number). 2157b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // esp[0]: return address. 2158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Output: 2159b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax: tagged double result. 2160b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // UNTAGGED case: 2161b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input:: 2162b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // esp[0]: return address. 2163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // xmm1: untagged double input argument 2164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Output: 2165b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // xmm1: untagged double result. 2166b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 216780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime_call; 216880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime_call_clear_stack; 2169b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label skip_cache; 2170b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const bool tagged = (argument_type_ == TAGGED); 2171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2172b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Test that eax is a number. 2173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label input_not_smi; 2174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loaded; 2175b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(esp, kPointerSize)); 21763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &input_not_smi, Label::kNear); 2177b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input is a smi. Untag and load it onto the FPU stack. 2178b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Then load the low and high words of the double into ebx, edx. 2179b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTagSize == 1); 2180b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sar(eax, 1); 2181b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(Operand(esp), Immediate(2 * kPointerSize)); 2182b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 0), eax); 2183b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fild_s(Operand(esp, 0)); 2184b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fst_d(Operand(esp, 0)); 2185b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(edx); 2186b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(ebx); 2187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&loaded, Label::kNear); 2188b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&input_not_smi); 2189b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if input is a HeapNumber. 2190b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 219144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 219244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(Operand(ebx), Immediate(factory->heap_number_map())); 2193b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_equal, &runtime_call); 2194b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input is a HeapNumber. Push it on the FPU stack and load its 2195b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // low and high words into ebx, edx. 2196b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2197b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); 2198b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset)); 2199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2200b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&loaded); 2201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 22028b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE4_1)) { 2203b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope sse4_scope(SSE4_1); 2204b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pextrd(Operand(edx), xmm1, 0x1); // copy xmm1[63..32] to edx. 2205b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 2206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pshufd(xmm0, xmm1, 0x1); 2207b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movd(Operand(edx), xmm0); 2208b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2209b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movd(Operand(ebx), xmm1); 2210b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 221180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2212b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ST[0] or xmm1 == double value 221380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx = low 32 bits of double value 221480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx = high 32 bits of double value 221580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compute hash (the shifts are arithmetic): 221680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); 221780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, ebx); 221880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(ecx, Operand(edx)); 221980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, ecx); 222080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sar(eax, 16); 222180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(ecx, Operand(eax)); 222280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, ecx); 222380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sar(eax, 8); 222480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(ecx, Operand(eax)); 222544f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize)); 222644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ and_(Operand(ecx), 222744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(TranscendentalCache::SubCache::kCacheSize - 1)); 222880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2229b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ST[0] or xmm1 == double value. 223080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx = low 32 bits of double value. 223180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx = high 32 bits of double value. 223280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx = TranscendentalCache::hash(double value). 223344f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference cache_array = 223444f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::transcendental_cache_array_address(masm->isolate()); 223544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, Immediate(cache_array)); 223644f0eee88ff00398ff7f715fab053374d808c90dSteve Block int cache_array_index = 223744f0eee88ff00398ff7f715fab053374d808c90dSteve Block type_ * sizeof(masm->isolate()->transcendental_cache()->caches_[0]); 223844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, Operand(eax, cache_array_index)); 223980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Eax points to the cache for the type type_. 224080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If NULL, the cache hasn't been initialized yet, so go through runtime. 224180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(eax, Operand(eax)); 224280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &runtime_call_clear_stack); 224380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG 224480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the layout of cache elements match expectations. 224544f0eee88ff00398ff7f715fab053374d808c90dSteve Block { TranscendentalCache::SubCache::Element test_elem[2]; 224680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_start = reinterpret_cast<char*>(&test_elem[0]); 224780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); 224880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); 224980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); 225080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); 225180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. 225280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(0, elem_in0 - elem_start); 225380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(kIntSize, elem_in1 - elem_start); 225480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(2 * kIntSize, elem_out - elem_start); 225580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 225680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 225780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find the address of the ecx'th entry in the cache, i.e., &eax[ecx*12]. 225880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(ecx, ecx, times_2, 0)); 225980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(eax, ecx, times_4, 0)); 226080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if cache matches: Double value is stored in uint32_t[2] array. 2261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label cache_miss; 226280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(ebx, Operand(ecx, 0)); 2263257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &cache_miss, Label::kNear); 226480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, Operand(ecx, kIntSize)); 2265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &cache_miss, Label::kNear); 226680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Cache hit! 226780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(ecx, 2 * kIntSize)); 2268b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2269b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp(0); 2270b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(kPointerSize); 2271b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 2272b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2273b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 2274b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 227580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 227680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&cache_miss); 227780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Update cache with new value. 227880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We are short on registers, so use no_reg as scratch. 227980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // This gives slightly larger code. 2280b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2281b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack); 2282b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 2283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); 2284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(Operand(esp), Immediate(kDoubleSize)); 2285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(Operand(esp, 0), xmm1); 2286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fld_d(Operand(esp, 0)); 2287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(Operand(esp), Immediate(kDoubleSize)); 2288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 228980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateOperation(masm); 229080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(ecx, 0), ebx); 229180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(ecx, kIntSize), edx); 229280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(ecx, 2 * kIntSize), eax); 229380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2294b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2295b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(kPointerSize); 2296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 2297b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2298b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 2299b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2300b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Skip cache and return answer directly, only in untagged case. 2301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_cache); 2302b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(Operand(esp), Immediate(kDoubleSize)); 2303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(Operand(esp, 0), xmm1); 2304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fld_d(Operand(esp, 0)); 2305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateOperation(masm); 2306b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(Operand(esp, 0)); 2307b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, Operand(esp, 0)); 2308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(Operand(esp), Immediate(kDoubleSize)); 2309b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // We return the value in xmm1 without adding it to the cache, but 2310b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // we cause a scavenging GC so that future allocations will succeed. 2311b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ EnterInternalFrame(); 2312b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate an unused object bigger than a HeapNumber. 2313b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(2 * kDoubleSize))); 2314b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); 2315b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ LeaveInternalFrame(); 2316b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 2317b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 231880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2319b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Call runtime, doing whatever allocation and cleanup is necessary. 2320b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2321b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&runtime_call_clear_stack); 2322b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp(0); 2323b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&runtime_call); 232444f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference runtime = 232544f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference(RuntimeFunction(), masm->isolate()); 232644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ TailCallExternalReference(runtime, 1, 1); 2327b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 2328b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&runtime_call_clear_stack); 2329b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&runtime_call); 2330b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); 2331b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm1); 2332b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ EnterInternalFrame(); 2333b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(eax); 2334b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CallRuntime(RuntimeFunction(), 1); 2335b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ LeaveInternalFrame(); 2336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2337b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 2338b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 233980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 234080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 234180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 234280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian MonsenRuntime::FunctionId TranscendentalCacheStub::RuntimeFunction() { 234380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen switch (type_) { 234480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case TranscendentalCache::SIN: return Runtime::kMath_sin; 234580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case TranscendentalCache::COS: return Runtime::kMath_cos; 2346b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case TranscendentalCache::LOG: return Runtime::kMath_log; 234780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen default: 234880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen UNIMPLEMENTED(); 234980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return Runtime::kAbort; 235080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 235180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 235280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 235380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 235480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) { 235580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Only free register is edi. 2356b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input value is on FP stack, and also in ebx/edx. 2357b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input value is possibly in xmm1. 2358b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Address of result (a newly allocated HeapNumber) may be in eax. 2359b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { 2360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Both fsin and fcos require arguments in the range +/-2^63 and 2361b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // return NaN for infinities and NaN. They can share all code except 2362b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // the actual fsin/fcos operation. 2363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label in_range, done; 2364b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If argument is outside the range -2^63..2^63, fsin/cos doesn't 2365b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // work. We must reduce it to the appropriate range. 2366b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edi, edx); 2367b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ and_(Operand(edi), Immediate(0x7ff00000)); // Exponent only. 2368b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch int supported_exponent_limit = 2369b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift; 2370b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(Operand(edi), Immediate(supported_exponent_limit)); 2371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, &in_range, Label::kNear); 2372b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for infinity and NaN. Both return NaN for sin. 2373b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(Operand(edi), Immediate(0x7ff00000)); 2374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_nan_result; 2375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &non_nan_result, Label::kNear); 2376b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input is +/-Infinity or NaN. Result is NaN. 2377b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp(0); 2378b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // NaN is represented by 0x7ff8000000000000. 2379b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(0x7ff80000)); 2380b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(0)); 2381b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fld_d(Operand(esp, 0)); 2382b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(Operand(esp), Immediate(2 * kPointerSize)); 2383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 238480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_nan_result); 238680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Use fpmod to restrict argument to the range +/-2*PI. 2388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edi, eax); // Save eax before using fnstsw_ax. 2389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fldpi(); 2390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fadd(0); 2391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fld(1); 2392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // FPU Stack: input, 2*pi, input. 2393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch { 2394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label no_exceptions; 2395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fwait(); 2396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fnstsw_ax(); 2397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Clear if Illegal Operand or Zero Division exceptions are set. 2398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(Operand(eax), Immediate(5)); 2399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &no_exceptions, Label::kNear); 2400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fnclex(); 2401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&no_exceptions); 2402257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 240380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute st(0) % st(1) 2405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch { 2406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label partial_remainder_loop; 2407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&partial_remainder_loop); 2408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fprem1(); 2409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fwait(); 2410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fnstsw_ax(); 2411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(Operand(eax), Immediate(0x400 /* C2 */)); 2412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If C2 is set, computation only has partial result. Loop to 2413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // continue computation. 2414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &partial_remainder_loop); 2415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 2416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // FPU Stack: input, 2*pi, input % 2*pi 2417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fstp(2); 2418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fstp(0); 2419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(eax, edi); // Restore eax (allocated HeapNumber pointer). 242080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // FPU Stack: input % 2*pi 2422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&in_range); 2423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (type_) { 2424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case TranscendentalCache::SIN: 2425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fsin(); 2426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 2427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case TranscendentalCache::COS: 2428257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fcos(); 2429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 2430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 2431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 243280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 2433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&done); 2434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 2435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(type_ == TranscendentalCache::LOG); 2436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fldln2(); 2437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fxch(); 2438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fyl2x(); 243980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 244080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 244180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 244280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 244380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Input: edx, eax are the left and right objects of a bit op. 244480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Output: eax, ecx are left and right integers for a bit op. 244580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm, 244680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool use_sse3, 244780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* conversion_failure) { 244880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check float operands. 244980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label arg1_is_object, check_undefined_arg1; 245080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label arg2_is_object, check_undefined_arg2; 245180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label load_arg2, done; 245280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 245380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Test if arg1 is a Smi. 245469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfNotSmi(edx, &arg1_is_object, Label::kNear); 245580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 245680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edx); 245780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_arg2); 245880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 245980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the argument is undefined it converts to zero (ECMA-262, section 9.5). 246080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_undefined_arg1); 246144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 246244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(edx, factory->undefined_value()); 246380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, conversion_failure); 246480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Immediate(0)); 246580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_arg2); 246680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 246780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&arg1_is_object); 246880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 246944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(ebx, factory->heap_number_map()); 247080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &check_undefined_arg1); 247180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 247280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the untagged integer version of the edx heap number in ecx. 2473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch IntegerConvert(masm, edx, use_sse3, conversion_failure); 247480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, ecx); 247580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 247680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Here edx has the untagged integer, eax has a Smi or a heap number. 247780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_arg2); 247880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 247980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Test if arg2 is a Smi. 248069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfNotSmi(eax, &arg2_is_object, Label::kNear); 248180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 248280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(eax); 248380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, eax); 248480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&done); 248580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 248680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the argument is undefined it converts to zero (ECMA-262, section 9.5). 248780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_undefined_arg2); 248844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, factory->undefined_value()); 248980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, conversion_failure); 249080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(0)); 249180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&done); 249280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 249380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&arg2_is_object); 249480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 249544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(ebx, factory->heap_number_map()); 249680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &check_undefined_arg2); 249780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 249880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the untagged integer version of the eax heap number in ecx. 2499257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch IntegerConvert(masm, eax, use_sse3, conversion_failure); 250080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 250180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, edx); 250280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 250380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 250480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2505b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckLoadedIntegersWereInt32(MacroAssembler* masm, 2506b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch bool use_sse3, 2507b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* not_int32) { 2508b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return; 2509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2511b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 251280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, 251380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register number) { 2514257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_smi, done; 251580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 25163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(number, &load_smi, Label::kNear); 251780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); 2518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 251980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 252080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi); 252180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(number); 252280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(number); 252380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 252480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(number); 252580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 252680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 252780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 252880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 252980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 253080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm) { 2531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_smi_edx, load_eax, load_smi_eax, done; 253280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in edx into xmm0. 25333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); 253480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 253580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 253680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_eax); 253780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in eax into xmm1. 25383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); 253980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2540257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 254180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 254280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_edx); 254380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edx); // Untag smi before converting to float. 254480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtsi2sd(xmm0, Operand(edx)); 254580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(edx); // Retag smi for heap number overwriting test. 254680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_eax); 254780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 254880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_eax); 254980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(eax); // Untag smi before converting to float. 255080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtsi2sd(xmm1, Operand(eax)); 255180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(eax); // Retag smi for heap number overwriting test. 255280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 255380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 255480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 255580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 255680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 255780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm, 255880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_numbers) { 2559257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; 256080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in edx into xmm0, or branch to not_numbers. 25613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); 256244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 256344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map()); 256480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_numbers); // Argument in edx is not a number. 256580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 256680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_eax); 256780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in eax into xmm1, or branch to not_numbers. 25683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); 256944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map()); 2570257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &load_float_eax, Label::kNear); 257180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(not_numbers); // Argument in eax is not a number. 257280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_edx); 257380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edx); // Untag smi before converting to float. 257480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtsi2sd(xmm0, Operand(edx)); 257580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(edx); // Retag smi for heap number overwriting test. 257680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_eax); 257780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_eax); 257880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(eax); // Untag smi before converting to float. 257980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtsi2sd(xmm1, Operand(eax)); 258080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(eax); // Retag smi for heap number overwriting test. 2581257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 258280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_float_eax); 258380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 258480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 258580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 258680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 258780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 258880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Smis(MacroAssembler* masm, 258980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 259080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const Register left = edx; 259180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const Register right = eax; 259280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, left); 259380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(right)); // We're about to clobber scratch. 259480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 259580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtsi2sd(xmm0, Operand(scratch)); 259680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 259780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, right); 259880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 259980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cvtsi2sd(xmm1, Operand(scratch)); 260080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 260180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 260280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2603b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm, 2604b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* non_int32, 2605b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register scratch) { 2606b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvttsd2si(scratch, Operand(xmm0)); 2607b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm2, Operand(scratch)); 2608b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm0, xmm2); 2609b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, non_int32); 2610b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(carry, non_int32); 2611b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvttsd2si(scratch, Operand(xmm1)); 2612b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm2, Operand(scratch)); 2613b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm1, xmm2); 2614b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, non_int32); 2615b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(carry, non_int32); 2616b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2617b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2618b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 261980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, 262080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch, 262180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ArgLocation arg_location) { 2622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_smi_1, load_smi_2, done_load_1, done; 262380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (arg_location == ARGS_IN_REGISTERS) { 262480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, edx); 262580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 262680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, Operand(esp, 2 * kPointerSize)); 262780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 26283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(scratch, &load_smi_1, Label::kNear); 262980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); 263080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done_load_1); 263180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 263280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (arg_location == ARGS_IN_REGISTERS) { 263380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, eax); 263480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 263580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, Operand(esp, 1 * kPointerSize)); 263680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 26373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(scratch, &load_smi_2, Label::kNear); 263880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); 2639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 264080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 264180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_1); 264280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 264380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(scratch); 264480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 264580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(scratch); 264680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&done_load_1); 264780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 264880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_2); 264980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 265080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(scratch); 265180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 265280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(scratch); 265380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 265480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 265580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 265680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 265780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 265880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatSmis(MacroAssembler* masm, 265980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 266080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const Register left = edx; 266180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const Register right = eax; 266280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, left); 266380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(right)); // We're about to clobber scratch. 266480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 266580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(scratch); 266680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 266780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 266880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, right); 266980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 267080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 0), scratch); 267180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 267280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(scratch); 267380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 267480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 267580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 267680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, 267780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* non_float, 267880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 2679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label test_other, done; 268080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Test if both operands are floats or smi -> scratch=k_is_float; 268180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Otherwise scratch = k_not_float. 26823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(edx, &test_other, Label::kNear); 268380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset)); 268444f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 268544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(scratch, factory->heap_number_map()); 268680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, non_float); // argument in edx is not a number -> NaN 268780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 268880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&test_other); 26893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &done, Label::kNear); 269080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset)); 269144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(scratch, factory->heap_number_map()); 269280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, non_float); // argument in eax is not a number -> NaN 269380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 269480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fall-through: Both operands are numbers. 269580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 269680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 269780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 269880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm, 2700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* non_int32) { 2701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return; 2702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2704b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2705b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid MathPowStub::Generate(MacroAssembler* masm) { 2706b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Registers are used as follows: 2707b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // edx = base 2708b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax = exponent 2709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ecx = temporary, result 2710b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 2712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label allocate_return, call_runtime; 2713b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Load input parameters. 2715b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, Operand(esp, 2 * kPointerSize)); 2716b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(esp, 1 * kPointerSize)); 2717b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Save 1 in xmm3 - we need this several times later on. 2719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Immediate(1)); 2720b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm3, Operand(ecx)); 2721b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label exponent_nonsmi; 2723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label base_nonsmi; 2724b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the exponent is a heap number go to that specific case. 27253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &exponent_nonsmi); 27263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(edx, &base_nonsmi); 2727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2728e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Optimized version when both exponent and base are smis. 2729b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label powi; 2730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(edx); 2731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm0, Operand(edx)); 2732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&powi); 2733b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // exponent is smi and base is a heapnumber. 2734b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&base_nonsmi); 273544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 2736b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(FieldOperand(edx, HeapObject::kMapOffset), 273744f0eee88ff00398ff7f715fab053374d808c90dSteve Block factory->heap_number_map()); 2738b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_equal, &call_runtime); 2739b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 2741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Optimized version of pow if exponent is a smi. 2743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // xmm0 contains the base. 2744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&powi); 2745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(eax); 2746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Save exponent in base as we need to check if exponent is negative later. 2748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // We know that base and exponent are in different registers. 2749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, eax); 2750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Get absolute value of exponent. 2752257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label no_neg; 2753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(eax, 0); 2754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(greater_equal, &no_neg, Label::kNear); 2755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ neg(eax); 2756b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&no_neg); 2757b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Load xmm1 with 1. 2759b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movsd(xmm1, xmm3); 2760257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label while_true; 2761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label no_multiply; 2762b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&while_true); 2764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ shr(eax, 1); 2765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_carry, &no_multiply, Label::kNear); 2766b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mulsd(xmm1, xmm0); 2767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&no_multiply); 2768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mulsd(xmm0, xmm0); 2769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &while_true); 2770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // base has the original value of the exponent - if the exponent is 2772b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // negative return 1/result. 2773b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(edx, Operand(edx)); 2774b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(positive, &allocate_return); 2775b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Special case if xmm1 has reached infinity. 2776b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Immediate(0x7FB00000)); 2777b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movd(xmm0, Operand(ecx)); 2778b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtss2sd(xmm0, xmm0); 2779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm0, xmm1); 2780b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(equal, &call_runtime); 2781b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ divsd(xmm3, xmm1); 2782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movsd(xmm1, xmm3); 2783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&allocate_return); 2784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2785b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // exponent (or both) is a heapnumber - no matter what we should now work 2786b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // on doubles. 2787b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&exponent_nonsmi); 2788b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(FieldOperand(eax, HeapObject::kMapOffset), 278944f0eee88ff00398ff7f715fab053374d808c90dSteve Block factory->heap_number_map()); 2790b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_equal, &call_runtime); 2791b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2792b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Test if exponent is nan. 2793b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm1, xmm1); 2794b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(parity_even, &call_runtime); 2795b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label base_not_smi; 2797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label handle_special_cases; 27983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(edx, &base_not_smi, Label::kNear); 2799b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(edx); 2800b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtsi2sd(xmm0, Operand(edx)); 2801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&handle_special_cases, Label::kNear); 2802b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2803b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&base_not_smi); 2804b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(FieldOperand(edx, HeapObject::kMapOffset), 280544f0eee88ff00398ff7f715fab053374d808c90dSteve Block factory->heap_number_map()); 2806b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_equal, &call_runtime); 2807b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); 2808b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ and_(ecx, HeapNumber::kExponentMask); 2809b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(Operand(ecx), Immediate(HeapNumber::kExponentMask)); 2810b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // base is NaN or +/-Infinity 2811b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(greater_equal, &call_runtime); 2812b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 2813b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2814b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // base is in xmm0 and exponent is in xmm1. 2815b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&handle_special_cases); 2816257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_minus_half; 2817b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Test for -0.5. 2818b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Load xmm2 with -0.5. 2819b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Immediate(0xBF000000)); 2820b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movd(xmm2, Operand(ecx)); 2821b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvtss2sd(xmm2, xmm2); 2822b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // xmm2 now has -0.5. 2823b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm2, xmm1); 2824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, ¬_minus_half, Label::kNear); 2825b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2826b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Calculates reciprocal of square root. 28271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // sqrtsd returns -0 when input is -0. ECMA spec requires +0. 2828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xorps(xmm1, xmm1); 28291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ addsd(xmm1, xmm0); 2830b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sqrtsd(xmm1, xmm1); 28311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ divsd(xmm3, xmm1); 28321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movsd(xmm1, xmm3); 2833b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&allocate_return); 2834b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2835b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Test for 0.5. 2836b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_minus_half); 2837b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Load xmm2 with 0.5. 2838b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3. 2839b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ addsd(xmm2, xmm3); 2840b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // xmm2 now has 0.5. 2841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm2, xmm1); 2842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_equal, &call_runtime); 2843b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Calculates square root. 28441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // sqrtsd returns -0 when input is -0. ECMA spec requires +0. 2845257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xorps(xmm1, xmm1); 28461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ addsd(xmm1, xmm0); 2847b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sqrtsd(xmm1, xmm1); 2848b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&allocate_return); 2850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(ecx, eax, edx, &call_runtime); 2851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm1); 2852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, ecx); 2853e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ret(2 * kPointerSize); 2854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2855b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&call_runtime); 2856b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); 2857b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 286080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { 286180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The key is in edx and the parameter count is in eax. 286280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 286380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The displacement is used for skipping the frame pointer on the 286480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stack. It is the offset of the last parameter (if any) relative 286580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // to the frame pointer. 286680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kDisplacement = 1 * kPointerSize; 286780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 286880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the key is a smi. 286980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow; 287069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfNotSmi(edx, &slow, Label::kNear); 287180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 287280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the calling frame is an arguments adaptor frame. 2873257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label adaptor; 287480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 287580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset)); 287680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 2877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &adaptor, Label::kNear); 287880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 287980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check index against formal parameters count limit passed in 288080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // through register eax. Use unsigned comparison to get negative 288180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // check for free. 288280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, Operand(eax)); 288369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(above_equal, &slow, Label::kNear); 288480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 288580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the argument from the stack and return it. 288680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize == 1); 288780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these. 288880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ebx, Operand(ebp, eax, times_2, 0)); 288980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ neg(edx); 289080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); 289180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 289280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 289380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Arguments adaptor case: Check index against actual arguments 289480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // limit found in the arguments adaptor frame. Use unsigned 289580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // comparison to get negative check for free. 289680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&adaptor); 289780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 289880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, Operand(ecx)); 289969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(above_equal, &slow, Label::kNear); 290080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 290180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the argument from the stack and return it. 290280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize == 1); 290380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these. 290480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ebx, Operand(ebx, ecx, times_2, 0)); 290580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ neg(edx); 290680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); 290780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 290880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 290980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case: Handle non-smi or out-of-bounds access to arguments 291080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // by calling the runtime system. 291180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 291280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ebx); // Return address. 291380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(edx); 291480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ebx); 291580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); 291680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 291780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 291880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 29193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { 292080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[0] : return address 292180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[4] : number of parameters 292280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[8] : receiver displacement 29233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] : function 29243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Check if the calling frame is an arguments adaptor frame. 29263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label runtime; 29273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 29283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 29293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 29303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(not_equal, &runtime, Label::kNear); 29313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Patch the arguments.length and the parameters pointer. 29333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 29343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ecx); 29353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edx, Operand(edx, ecx, times_2, 29363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch StandardFrameConstants::kCallerSPOffset)); 29373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(Operand(esp, 2 * kPointerSize), edx); 29383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&runtime); 29403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); 29413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch} 29423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { 29453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] : return address 29463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] : number of parameters (tagged) 29473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] : receiver displacement 29483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] : function 29493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = parameter count (tagged) 29513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, Operand(esp, 1 * kPointerSize)); 29523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Check if the calling frame is an arguments adaptor frame. 29543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // TODO(rossberg): Factor out some of the bits that are shared with the other 29553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Generate* functions. 29563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label runtime; 29573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label adaptor_frame, try_allocate; 29583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 29593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 29603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 29613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(equal, &adaptor_frame, Label::kNear); 29623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // No adaptor, parameter count = argument count. 29643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, ebx); 29653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(&try_allocate, Label::kNear); 29663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We have an adaptor frame. Patch the parameters pointer. 29683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&adaptor_frame); 29693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 29703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edx, Operand(edx, ecx, times_2, 29713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch StandardFrameConstants::kCallerSPOffset)); 29723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(Operand(esp, 2 * kPointerSize), edx); 29733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = parameter count (tagged) 29753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 29763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] = parameter count (tagged) 29773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = address of receiver argument 29783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Compute the mapped parameter count = min(ebx, ecx) in ebx. 29793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(ebx, Operand(ecx)); 29803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(less_equal, &try_allocate, Label::kNear); 29813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, ecx); 29823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&try_allocate); 29843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Save mapped parameter count. 29863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(ebx); 29873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Compute the sizes of backing store, parameter map, and arguments object. 29893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 1. Parameter map, has 2 extra words containing context and backing store. 29903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int kParameterMapHeaderSize = 29913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch FixedArray::kHeaderSize + 2 * kPointerSize; 29923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label no_parameter_map; 29933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ test(ebx, Operand(ebx)); 29943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(zero, &no_parameter_map, Label::kNear); 29953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize)); 29963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&no_parameter_map); 29973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 29983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 2. Backing store. 29993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); 30003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 3. Arguments object. 30023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(Operand(ebx), Immediate(Heap::kArgumentsObjectSize)); 30033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Do the allocation of all three objects in one go. 30053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT); 30063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // eax = address of new object(s) (tagged) 30083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 30093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = mapped parameter count (tagged) 30103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = parameter count (tagged) 30113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] = address of receiver argument 30123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Get the arguments boilerplate from the current (global) context into edi. 30133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label has_mapped_parameters, copy; 30143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 30153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); 30163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, Operand(esp, 0 * kPointerSize)); 30173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ test(ebx, Operand(ebx)); 30183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(not_zero, &has_mapped_parameters, Label::kNear); 30193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, Operand(edi, 30203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX))); 30213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(©, Label::kNear); 30223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&has_mapped_parameters); 30243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, Operand(edi, 30253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX))); 30263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(©); 30273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // eax = address of new object (tagged) 30293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = mapped parameter count (tagged) 30303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 30313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edi = address of boilerplate object (tagged) 30323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = mapped parameter count (tagged) 30333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = parameter count (tagged) 30343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] = address of receiver argument 30353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy the JS object part. 30363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { 30373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, FieldOperand(edi, i)); 30383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(eax, i), edx); 30393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch } 30403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Setup the callee in-object property. 30423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); 30433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, Operand(esp, 4 * kPointerSize)); 30443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(eax, JSObject::kHeaderSize + 30453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsCalleeIndex * kPointerSize), 30463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch edx); 30473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Use the length (smi tagged) and set that as an in-object property too. 30493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); 30503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(eax, JSObject::kHeaderSize + 30513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsLengthIndex * kPointerSize), 30523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch ecx); 30533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Setup the elements pointer in the allocated arguments object. 30553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // If we allocated a parameter map, edi will point there, otherwise to the 30563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // backing store. 30573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edi, Operand(eax, Heap::kArgumentsObjectSize)); 30583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); 30593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // eax = address of new object (tagged) 30613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = mapped parameter count (tagged) 30623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 30633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edi = address of parameter map or backing store (tagged) 30643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = mapped parameter count (tagged) 30653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = parameter count (tagged) 30663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] = address of receiver argument 30673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Free a register. 30683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(eax); 30693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Initialize parameter map. If there are no mapped arguments, we're done. 30713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label skip_parameter_map; 30723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ test(ebx, Operand(ebx)); 30733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(zero, &skip_parameter_map); 307480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 30753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kMapOffset), 30763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Immediate(FACTORY->non_strict_arguments_elements_map())); 30773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2)))); 30783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax); 30793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi); 30803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize)); 30813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax); 30823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 30833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy the parameter slots and the holes in the arguments. 30843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We need to fill in mapped_parameter_count slots. They index the context, 30853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // where parameters are stored in reverse order, at 30863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 30873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // The mapped parameter thus need to get indices 30883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS+parameter_count-1 .. 30893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count 30903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We loop from right to left. 30913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label parameters_loop, parameters_test; 30923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(ecx); 30933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(eax, Operand(esp, 2 * kPointerSize)); 30943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); 30953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(ebx, Operand(esp, 4 * kPointerSize)); 30963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(ebx, Operand(eax)); 30973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, FACTORY->the_hole_value()); 30983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, edi); 30993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize)); 31003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // eax = loop variable (tagged) 31013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = mapping index (tagged) 31023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = the hole value 31033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edx = address of parameter map (tagged) 31043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edi = address of backing store (tagged) 31053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = argument count (tagged) 31063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] = address of new object (tagged) 31073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = mapped parameter count (tagged) 31083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[16] = parameter count (tagged) 31093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[20] = address of receiver argument 31103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(¶meters_test, Label::kNear); 31113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 31123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(¶meters_loop); 31133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(Operand(eax), Immediate(Smi::FromInt(1))); 31143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx); 31153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx); 31163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(Operand(ebx), Immediate(Smi::FromInt(1))); 31173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(¶meters_test); 31183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ test(eax, Operand(eax)); 31193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(not_zero, ¶meters_loop, Label::kNear); 31203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ pop(ecx); 31213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 31223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&skip_parameter_map); 31233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 31243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 31253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edi = address of backing store (tagged) 31263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = address of new object (tagged) 31273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] = mapped parameter count (tagged) 31283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] = parameter count (tagged) 31293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[16] = address of receiver argument 31303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy arguments header and remaining slots (if there are any). 31313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kMapOffset), 31323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Immediate(FACTORY->fixed_array_map())); 31333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); 31343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 31353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label arguments_loop, arguments_test; 31363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, Operand(esp, 1 * kPointerSize)); 31373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, Operand(esp, 4 * kPointerSize)); 31383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(Operand(edx), ebx); // Is there a smarter way to do negative scaling? 31393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(Operand(edx), ebx); 31403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(&arguments_test, Label::kNear); 31413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 31423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&arguments_loop); 31433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(Operand(edx), Immediate(kPointerSize)); 31443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(eax, Operand(edx, 0)); 31453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax); 31463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(Operand(ebx), Immediate(Smi::FromInt(1))); 31473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 31483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&arguments_test); 31493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(ebx, Operand(ecx)); 31503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(less, &arguments_loop, Label::kNear); 31513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 31523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Restore. 31533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ pop(eax); // Address of arguments object. 31543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ pop(ebx); // Parameter count. 31553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 31563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Return and remove the on-stack parameters. 31573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ret(3 * kPointerSize); 31583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 31593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Do the runtime call to allocate the arguments object. 31603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&runtime); 31613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ pop(eax); // Remove saved parameter count. 31623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ecx); // Patch argument count. 31633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); 31643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch} 31653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 31663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 31673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { 31683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] : return address 31693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] : number of parameters 31703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] : receiver displacement 31713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] : function 317280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 317380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the calling frame is an arguments adaptor frame. 317480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label adaptor_frame, try_allocate, runtime; 317580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 317680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 317780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 317869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(equal, &adaptor_frame, Label::kNear); 317980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 318080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the length from the frame. 318180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esp, 1 * kPointerSize)); 318269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&try_allocate, Label::kNear); 318380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 318480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Patch the arguments.length and the parameters pointer. 318580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&adaptor_frame); 318680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 318780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 1 * kPointerSize), ecx); 31883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edx, Operand(edx, ecx, times_2, 31893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch StandardFrameConstants::kCallerSPOffset)); 319080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 2 * kPointerSize), edx); 319180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 319280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try the new space allocation. Start out with computing the size of 319380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the arguments object and the elements array. 3194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label add_arguments_object; 319580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&try_allocate); 319680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Operand(ecx)); 3197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &add_arguments_object, Label::kNear); 319880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize)); 319980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&add_arguments_object); 32003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(Operand(ecx), Immediate(Heap::kArgumentsObjectSizeStrict)); 320180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 320280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the allocation of both objects in one go. 320380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT); 320480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 320580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the arguments boilerplate from the current (global) context. 320680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 320780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); 32083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int offset = 32093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX); 32103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, Operand(edi, offset)); 321180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 321280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy the JS object part. 321380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { 321480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(edi, i)); 321580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, i), ebx); 321680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 321780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 321880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the length (smi tagged) and set that as an in-object property too. 321944f0eee88ff00398ff7f715fab053374d808c90dSteve Block STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); 322080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esp, 1 * kPointerSize)); 322144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(FieldOperand(eax, JSObject::kHeaderSize + 32223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsLengthIndex * kPointerSize), 322344f0eee88ff00398ff7f715fab053374d808c90dSteve Block ecx); 322480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 322580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If there are no actual arguments, we're done. 322680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label done; 322780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Operand(ecx)); 322869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &done, Label::kNear); 322980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 323080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the parameters pointer from the stack. 323180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 2 * kPointerSize)); 323280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 323380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Setup the elements pointer in the allocated arguments object and 323480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // initialize the header in the elements fixed array. 32353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict)); 323680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); 323780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(edi, FixedArray::kMapOffset), 32383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Immediate(FACTORY->fixed_array_map())); 323944f0eee88ff00398ff7f715fab053374d808c90dSteve Block 324080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); 324180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Untag the length for the loop below. 324280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ecx); 324380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 324480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy the fixed array slots. 3245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop; 324680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 324780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(edx, -1 * kPointerSize)); // Skip receiver. 324880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx); 324980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edi), Immediate(kPointerSize)); 325080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(edx), Immediate(kPointerSize)); 325180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ dec(ecx); 325280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &loop); 325380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 325480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameters. 325580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 325680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 325780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 325880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the runtime call to allocate the arguments object. 325980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 32603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); 326180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 326280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 326380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 326480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid RegExpExecStub::Generate(MacroAssembler* masm) { 326580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump directly to runtime if native RegExp is not selected at compile 326680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // time or if regexp entry in generated code is turned off runtime switch or 326780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // at compilation. 326880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef V8_INTERPRETED_REGEXP 326980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 327080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else // V8_INTERPRETED_REGEXP 327180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!FLAG_regexp_entry_native) { 327280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 327380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return; 327480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 327580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 327680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 327780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[0]: return address 327880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[4]: last_match_info (expected JSArray) 327980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[8]: previous index 328080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[12]: subject string 328180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[16]: JSRegExp object 328280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 328380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kLastMatchInfoOffset = 1 * kPointerSize; 328480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kPreviousIndexOffset = 2 * kPointerSize; 328580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kSubjectOffset = 3 * kPointerSize; 328680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kJSRegExpOffset = 4 * kPointerSize; 328780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 328880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime, invoke_regexp; 328980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 329080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Ensure that a RegExp stack is allocated. 329180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference address_of_regexp_stack_memory_address = 329244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_regexp_stack_memory_address( 329344f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 329480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference address_of_regexp_stack_memory_size = 329544f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_regexp_stack_memory_size(masm->isolate()); 329680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); 329780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ebx, Operand(ebx)); 3298257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &runtime); 329980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 330080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the first argument is a JSRegExp object. 330180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kJSRegExpOffset)); 330280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 33033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &runtime); 330480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); 330580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 330680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the RegExp has been compiled (data contains a fixed array). 330780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); 330880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 330980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Immediate(kSmiTagMask)); 331080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected"); 331180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); 331280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); 331380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 331480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 331580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 331680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. 331780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset)); 331880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand(ebx), Immediate(Smi::FromInt(JSRegExp::IRREGEXP))); 331980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 332080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 332180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 332280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the number of captures fit in the static offsets vector buffer. 332380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); 332480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate number of capture registers (number_of_captures + 1) * 2. This 332580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // uses the asumption that smis are 2 * their untagged value. 332680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 332780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 332880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), Immediate(2)); // edx was a smi. 332980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the static offsets vector buffer is large enough. 333080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize); 333180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above, &runtime); 333280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 333380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 333480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: Number of capture registers 333580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the second argument is a string. 333680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kSubjectOffset)); 33373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &runtime); 333880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); 333980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(NegateCondition(is_string), &runtime); 334080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the length of the string to ebx. 334180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); 334280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 334380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: Length of subject string as a smi 334480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 334580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: Number of capture registers 334680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the third argument is a positive smi less than the subject 334780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // string length. A negative value will be greater (unsigned comparison). 334880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kPreviousIndexOffset)); 33493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &runtime); 335080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, Operand(ebx)); 335180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &runtime); 335280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 335380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 335480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: Number of capture registers 335580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the fourth object is a JSArray object. 335680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kLastMatchInfoOffset)); 33573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &runtime); 335880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); 335980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 336080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the JSArray is in fast case. 336180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); 336280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset)); 336344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 336444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, factory->fixed_array_map()); 336580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 336680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the last match info has space for the capture registers and the 336780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // additional information. 336880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset)); 336980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(eax); 337080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), Immediate(RegExpImpl::kLastMatchOverhead)); 337180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, Operand(eax)); 337280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(greater, &runtime); 337380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 337469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Reset offset for possibly sliced string. 337569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(edi, Immediate(0)); 337680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 337780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the representation and encoding of the subject string. 337880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label seq_ascii_string, seq_two_byte_string, check_code; 337980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kSubjectOffset)); 338080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 338180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 338280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // First check for flat two byte string. 338380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(ebx, 338480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask); 338580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); 338669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &seq_two_byte_string, Label::kNear); 338780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Any other flat string must be a flat ascii string. 338869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ and_(Operand(ebx), 338980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(kIsNotStringMask | kStringRepresentationMask)); 339069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &seq_ascii_string, Label::kNear); 339180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 339269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Check for flat cons string or sliced string. 339380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // A flat cons string is a cons string where the second part is the empty 339480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // string. In that case the subject string is just the first part of the cons 339580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // string. Also in this case the first part of the cons string is known to be 339680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // a sequential string or an external string. 339769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // In the case of a sliced string its offset has to be taken into account. 339869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label cons_string, check_encoding; 339969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kConsStringTag < kExternalStringTag); 340069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); 340169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(Operand(ebx), Immediate(kExternalStringTag)); 340269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(less, &cons_string); 340369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(equal, &runtime); 340469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 340569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // String is sliced. 340669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset)); 340769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset)); 340869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // edi: offset of sliced string, smi-tagged. 340969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // eax: parent string. 341069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&check_encoding, Label::kNear); 341169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // String is a cons string, check whether it is flat. 341269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&cons_string); 341369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(FieldOperand(eax, ConsString::kSecondOffset), factory->empty_string()); 341480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 341580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); 341669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&check_encoding); 341780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 341869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // eax: first part of cons string or parent of sliced string. 341969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // ebx: map of first part of cons string or map of parent of sliced string. 342069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Is first part of cons or parent of slice a flat two byte string? 342180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), 342280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen kStringRepresentationMask | kStringEncodingMask); 342380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); 342469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &seq_two_byte_string, Label::kNear); 342580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Any other flat string must be ascii. 342680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), 342780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen kStringRepresentationMask); 342880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &runtime); 342980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 343080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&seq_ascii_string); 343180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: subject string (flat ascii) 343280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 343380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset)); 343469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(ecx, Immediate(1)); // Type is ascii. 343569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&check_code, Label::kNear); 343680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 343780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&seq_two_byte_string); 343880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: subject string (flat two byte) 343980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 344080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset)); 344169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(ecx, Immediate(0)); // Type is two byte. 344280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 344380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_code); 344480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the irregexp code has been generated for the actual string 344580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // encoding. If it has, the field contains a code object otherwise it contains 3446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // a smi (code flushing support). 3447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfSmi(edx, &runtime); 344880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 344980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: subject string 345080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: code 345169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // ecx: encoding of subject string (1 if ascii, 0 if two_byte); 345280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load used arguments before starting to push arguments for call to native 345380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // RegExp code to avoid handling changing stack height. 345480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(esp, kPreviousIndexOffset)); 345580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ebx); // Previous index from smi. 345680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 345780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: subject string 345880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: previous index 345980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: code 346069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // ecx: encoding of subject string (1 if ascii 0 if two_byte); 346180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // All checks done. Now push arguments for native regexp code. 346244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 346344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->regexp_entry_native(), 1); 346480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 346544f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Isolates: note we add an additional parameter here (isolate pointer). 346644f0eee88ff00398ff7f715fab053374d808c90dSteve Block static const int kRegExpExecuteArguments = 8; 3467e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ EnterApiExitFrame(kRegExpExecuteArguments); 346880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 346944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Argument 8: Pass current isolate address. 347044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(Operand(esp, 7 * kPointerSize), 347144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(ExternalReference::isolate_address())); 347244f0eee88ff00398ff7f715fab053374d808c90dSteve Block 347380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 7: Indicate that this is a direct call from JavaScript. 347480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 6 * kPointerSize), Immediate(1)); 347580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 347680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 6: Start (high end) of backtracking stack memory area. 347769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(esi, Operand::StaticVariable(address_of_regexp_stack_memory_address)); 347869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ add(esi, Operand::StaticVariable(address_of_regexp_stack_memory_size)); 347969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(Operand(esp, 5 * kPointerSize), esi); 348080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 348180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 5: static offsets vector buffer. 348280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 4 * kPointerSize), 348344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(ExternalReference::address_of_static_offsets_vector( 348444f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()))); 348580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 348669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Argument 2: Previous index. 348769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(Operand(esp, 1 * kPointerSize), ebx); 348869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 348969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Argument 1: Original subject string. 349069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // The original subject is in the previous stack frame. Therefore we have to 349169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // use ebp, which points exactly to one pointer size below the previous esp. 349269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // (Because creating a new stack frame pushes the previous ebp onto the stack 349369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // and thereby moves up esp by one kPointerSize.) 349469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(esi, Operand(ebp, kSubjectOffset + kPointerSize)); 349569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(Operand(esp, 0 * kPointerSize), esi); 349669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 349769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // esi: original subject string 349869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // eax: underlying subject string 349969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // ebx: previous index 350069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // ecx: encoding of subject string (1 if ascii 0 if two_byte); 350169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // edx: code 350280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 4: End of string data 350380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 3: Start of string data 350469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Prepare start and end index of the input. 350569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Load the length from the original sliced string if that is the case. 350669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(esi, FieldOperand(esi, String::kLengthOffset)); 350769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ add(esi, Operand(edi)); // Calculate input end wrt offset. 350869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ SmiUntag(edi); 350969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ add(ebx, Operand(edi)); // Calculate input start wrt offset. 351069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 351169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // ebx: start index of the input string 351269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // esi: end index of the input string 3513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label setup_two_byte, setup_rest; 351469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ test(ecx, Operand(ecx)); 3515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &setup_two_byte, Label::kNear); 351669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ SmiUntag(esi); 351769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ lea(ecx, FieldOperand(eax, esi, times_1, SeqAsciiString::kHeaderSize)); 351880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. 351980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); 352080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. 3521257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&setup_rest, Label::kNear); 352280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 352380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&setup_two_byte); 352480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 352569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kSmiTagSize == 1); // esi is smi (powered by 2). 352669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize)); 352780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. 352880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); 352980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. 353080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 353180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&setup_rest); 353280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 353380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate the code entry and call it. 353480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag)); 3535e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ call(Operand(edx)); 3536e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3537e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Drop arguments and come back to JS mode. 3538e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LeaveApiExitFrame(); 353980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 354080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the result. 354180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label success; 354280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS); 3543257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &success); 354480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label failure; 354580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); 3546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &failure); 354780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); 354880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If not exception it can only be retry. Handle that in the runtime system. 354980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 355080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result must now be exception. If there is no pending exception already a 355180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stack overflow (on the backtrack stack) was detected in RegExp code but 355280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // haven't created the exception yet. Handle that in the runtime system. 355380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // TODO(592): Rerunning the RegExp to get the stack overflow exception. 3554589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch ExternalReference pending_exception(Isolate::kPendingExceptionAddress, 355544f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 3556e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(edx, 355744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Operand::StaticVariable(ExternalReference::the_hole_value_location( 355844f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()))); 3559e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(eax, Operand::StaticVariable(pending_exception)); 3560e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cmp(edx, Operand(eax)); 356180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &runtime); 3562e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // For exception, throw the exception again. 3563e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3564e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Clear the pending exception variable. 3565e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(Operand::StaticVariable(pending_exception), edx); 3566e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3567e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Special handling of termination exceptions which are uncatchable 3568e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // by javascript code. 356944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, factory->termination_exception()); 3570e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label throw_termination_exception; 357169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(equal, &throw_termination_exception, Label::kNear); 3572e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3573e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Handle normal exception by following handler chain. 3574e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Throw(eax); 3575e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3576e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&throw_termination_exception); 3577e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ThrowUncatchable(TERMINATION, eax); 3578e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 357980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&failure); 3580e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // For failure to match, return null. 358144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(Operand(eax), factory->null_value()); 358280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(4 * kPointerSize); 358380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 358480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load RegExp data. 358580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&success); 358680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kJSRegExpOffset)); 358780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); 358880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); 358980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate number of capture registers (number_of_captures + 1) * 2. 359080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 359180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 359280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), Immediate(2)); // edx was a smi. 359380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 359480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: Number of capture registers 359580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load last_match_info which is still known to be a fast case JSArray. 359680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kLastMatchInfoOffset)); 359780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); 359880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 359980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: last_match_info backing store (FixedArray) 360080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: number of capture registers 360180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store the capture count. 360280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(edx); // Number of capture registers to smi. 360380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ebx, RegExpImpl::kLastCaptureCountOffset), edx); 360480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edx); // Number of capture registers back from smi. 360580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store last subject and last input. 360680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kSubjectOffset)); 360780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax); 360880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, ebx); 360980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ RecordWrite(ecx, RegExpImpl::kLastSubjectOffset, eax, edi); 361080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kSubjectOffset)); 361180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax); 361280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, ebx); 361380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ RecordWrite(ecx, RegExpImpl::kLastInputOffset, eax, edi); 361480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 361580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the static offsets vector filled by the native regexp code. 361680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference address_of_static_offsets_vector = 361744f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_static_offsets_vector(masm->isolate()); 361880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(address_of_static_offsets_vector)); 361980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 362080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: last_match_info backing store (FixedArray) 362180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: offsets vector 362280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: number of capture registers 3623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label next_capture, done; 362480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Capture register counter starts from number of capture registers and 362580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // counts down until wraping after zero. 362680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&next_capture); 362780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(edx), Immediate(1)); 3628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(negative, &done, Label::kNear); 362980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the value from the static offsets vector buffer. 363080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, Operand(ecx, edx, times_int_size, 0)); 363180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(edi); 363280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store the smi value in the last match info. 363380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ebx, 363480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen edx, 363580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_pointer_size, 363680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen RegExpImpl::kFirstCaptureOffset), 363780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen edi); 363880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&next_capture); 363980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 364080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 364180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return last match info. 364280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kLastMatchInfoOffset)); 364380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(4 * kPointerSize); 364480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 364580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the runtime call to execute the regexp. 364680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 364780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 364880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif // V8_INTERPRETED_REGEXP 364980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 365080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 365180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3652b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid RegExpConstructResultStub::Generate(MacroAssembler* masm) { 3653b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const int kMaxInlineLength = 100; 3654b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label slowcase; 3655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done; 3656b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, Operand(esp, kPointerSize * 3)); 36573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(ebx, &slowcase); 3658b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(Operand(ebx), Immediate(Smi::FromInt(kMaxInlineLength))); 3659b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(above, &slowcase); 3660b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Smi-tagging is equivalent to multiplying by 2. 3661b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 3662b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTagSize == 1); 3663b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate RegExpResult followed by FixedArray with size in ebx. 3664b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // JSArray: [Map][empty properties][Elements][Length-smi][index][input] 3665b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Elements: [Map][Length][..elements..] 3666b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize, 3667b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch times_half_pointer_size, 3668b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ebx, // In: Number of elements (times 2, being a smi) 3669b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch eax, // Out: Start of allocation (tagged). 3670b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ecx, // Out: End of allocation. 3671b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch edx, // Scratch register 3672b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch &slowcase, 3673b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch TAG_OBJECT); 3674b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax: Start of allocated area, object-tagged. 3675b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3676b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set JSArray map to global.regexp_result_map(). 3677b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set empty properties FixedArray. 3678b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set elements to point to FixedArray allocated right after the JSArray. 3679b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Interleave operations for better latency. 3680b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX)); 368144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 368244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(ecx, Immediate(factory->empty_fixed_array())); 3683b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ lea(ebx, Operand(eax, JSRegExpResult::kSize)); 3684b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset)); 3685b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx); 3686b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx); 3687b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX)); 3688b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, HeapObject::kMapOffset), edx); 3689b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3690b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set input, index and length fields from arguments. 3691b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(esp, kPointerSize * 1)); 3692b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSRegExpResult::kInputOffset), ecx); 3693b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(esp, kPointerSize * 2)); 3694b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSRegExpResult::kIndexOffset), ecx); 3695b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(esp, kPointerSize * 3)); 3696b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSArray::kLengthOffset), ecx); 3697b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3698b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill out the elements FixedArray. 3699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax: JSArray. 3700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ebx: FixedArray. 3701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ecx: Number of elements in array, as smi. 3702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set map. 3704b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(ebx, HeapObject::kMapOffset), 370544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(factory->fixed_array_map())); 3706b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set length. 3707b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(ebx, FixedArray::kLengthOffset), ecx); 3708b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill contents of fixed-array with the-hole. 3709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(ecx); 371044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(edx, Immediate(factory->the_hole_value())); 3711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize)); 3712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill fixed array elements with hole. 3713b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax: JSArray. 3714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ecx: Number of elements to fill. 3715b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ebx: Start of elements in FixedArray. 3716b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // edx: the hole. 3717b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label loop; 3718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(ecx, Operand(ecx)); 3719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&loop); 3720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(less_equal, &done, Label::kNear); // Jump if ecx is negative or zero. 3721b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(Operand(ecx), Immediate(1)); 3722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(ebx, ecx, times_pointer_size, 0), edx); 3723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&loop); 3724b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3725b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&done); 3726b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(3 * kPointerSize); 3727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3728b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&slowcase); 3729b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); 3730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 3731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 373380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, 373480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register object, 373580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register result, 373680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 373780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 373880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool object_is_smi, 373980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_found) { 374080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Use of registers. Register result is used as a temporary. 374180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register number_string_cache = result; 374280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register mask = scratch1; 374380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch = scratch2; 374480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 374580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the number string cache. 374644f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference roots_address = 374744f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::roots_address(masm->isolate()); 374880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex)); 374980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(number_string_cache, 375080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Operand::StaticArray(scratch, times_pointer_size, roots_address)); 375180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make the hash mask from the length of the number string cache. It 375280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // contains two elements (number and string) for each cache entry. 375380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset)); 375480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shr(mask, kSmiTagSize + 1); // Untag length and divide it by two. 375580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(mask), Immediate(1)); // Make mask. 375680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 375780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate the entry in the number string cache. The hash value in the 375880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // number string cache for smis is just the smi value, and the hash for 375980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // doubles is the xor of the upper and lower words. See 376080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Heap::GetNumberStringCache. 3761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label smi_hash_calculated; 3762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_result_from_cache; 376380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (object_is_smi) { 376480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, object); 376580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 376680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 3767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_smi; 376880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 37693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(object, ¬_smi, Label::kNear); 377080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, object); 377180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 3772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&smi_hash_calculated, Label::kNear); 377380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_smi); 377480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(object, HeapObject::kMapOffset), 377544f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()->factory()->heap_number_map()); 377680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_found); 377780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(8 == kDoubleSize); 377880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset)); 377980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); 378080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Object is heap number and hash is now in scratch. Calculate cache index. 378180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(scratch, Operand(mask)); 378280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register index = scratch; 378380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register probe = mask; 378480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(probe, 378580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(number_string_cache, 378680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index, 378780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_twice_pointer_size, 378880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize)); 37893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(probe, not_found); 37908b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 379180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope fscope(SSE2); 379280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset)); 379380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset)); 379480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ucomisd(xmm0, xmm1); 379580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 379680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(object, HeapNumber::kValueOffset)); 379780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset)); 379880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ FCmp(); 379980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 380080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(parity_even, not_found); // Bail out if NaN is involved. 380180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_found); // The cache did not contain this value. 3802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&load_result_from_cache, Label::kNear); 380380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 380480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 380580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&smi_hash_calculated); 380680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Object is smi and hash is now in scratch. Calculate cache index. 380780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(scratch, Operand(mask)); 380880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register index = scratch; 380980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the entry is the smi we are looking for. 381080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(object, 381180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(number_string_cache, 381280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index, 381380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_twice_pointer_size, 381480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize)); 381580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_found); 381680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 381780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the result from the cache. 381880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_result_from_cache); 381980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result, 382080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(number_string_cache, 382180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index, 382280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_twice_pointer_size, 382380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize + kPointerSize)); 382444f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 382544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->number_to_string_native(), 1); 382680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 382780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 382880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 382980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::Generate(MacroAssembler* masm) { 383080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 383180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 383280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(esp, kPointerSize)); 383380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 383480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Generate code to lookup number in the number string cache. 383580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateLookupNumberStringCache(masm, ebx, eax, ecx, edx, false, &runtime); 383680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(1 * kPointerSize); 383780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 383880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 383980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle number to string in the runtime system if not found in the cache. 384080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1); 384180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 384280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 384380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 384480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic int NegativeComparisonResult(Condition cc) { 384580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(cc != equal); 384680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT((cc == less) || (cc == less_equal) 384780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen || (cc == greater) || (cc == greater_equal)); 384880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return (cc == greater || cc == greater_equal) ? LESS : GREATER; 384980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 385080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 385180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::Generate(MacroAssembler* masm) { 385280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 385380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 385469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label check_unequal_objects; 385580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 38560d5e116f6aee03185f237311a943491bb079a768Kristian Monsen // Compare two smis if required. 38570d5e116f6aee03185f237311a943491bb079a768Kristian Monsen if (include_smi_compare_) { 38580d5e116f6aee03185f237311a943491bb079a768Kristian Monsen Label non_smi, smi_done; 38590d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ mov(ecx, Operand(edx)); 38600d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ or_(ecx, Operand(eax)); 386169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfNotSmi(ecx, &non_smi, Label::kNear); 38620d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ sub(edx, Operand(eax)); // Return on the result of the subtraction. 386369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(no_overflow, &smi_done, Label::kNear); 3864f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch __ not_(edx); // Correct sign in case of overflow. edx is never 0 here. 38650d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ bind(&smi_done); 38660d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ mov(eax, edx); 38670d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ ret(0); 38680d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ bind(&non_smi); 38690d5e116f6aee03185f237311a943491bb079a768Kristian Monsen } else if (FLAG_debug_code) { 38700d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ mov(ecx, Operand(edx)); 38710d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ or_(ecx, Operand(eax)); 38720d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ test(ecx, Immediate(kSmiTagMask)); 38730d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ Assert(not_zero, "Unexpected smi operands."); 38740d5e116f6aee03185f237311a943491bb079a768Kristian Monsen } 38750d5e116f6aee03185f237311a943491bb079a768Kristian Monsen 387680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NOTICE! This code is only reached after a smi-fast-case check, so 387780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // it is certain that at least one operand isn't a smi. 387880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 387980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Identical objects can be compared fast, but there are some tricky cases 388080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // for NaN and undefined. 388180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen { 388280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label not_identical; 388380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, Operand(edx)); 388480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, ¬_identical); 388580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 388680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ != equal) { 388780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for undefined. undefined OP undefined is false even though 388880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // undefined == undefined. 3889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label check_for_nan; 389044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(edx, masm->isolate()->factory()->undefined_value()); 3891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &check_for_nan, Label::kNear); 389280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); 389380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 389480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_for_nan); 389580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 389680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 389744f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Test for NaN. Sadly, we can't just compare to factory->nan_value(), 389880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // so we do the second best thing - test it ourselves. 389980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Note: if cc_ != equal, never_nan_nan_ is not used. 390080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (never_nan_nan_ && (cc_ == equal)) { 390180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 390280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 390380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 3904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label heap_number; 390580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(edx, HeapObject::kMapOffset), 390644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(masm->isolate()->factory()->heap_number_map())); 3907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &heap_number, Label::kNear); 390880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ != equal) { 390980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call runtime on identical JSObjects. Otherwise return equal. 39103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); 391180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, ¬_identical); 391280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 391380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 391480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 391580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 391680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&heap_number); 391780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // It is a heap number, so return non-equal if it's NaN and equal if 391880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // it's not NaN. 391980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The representation of NaN values has all exponent bits (52..62) set, 392080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and not all mantissa bits (0..51) clear. 392180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We only accept QNaNs, which have bit 51 set. 392280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read top bits of double representation (second word of value). 392380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 392480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., 392580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // all bits in the mask are set. We only need to check the word 392680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // that contains the exponent and high bit of the mantissa. 392780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0); 392880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); 39299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Set(eax, Immediate(0)); 393080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Shift value and mask so kQuietNaNHighBitsMask applies to topmost 393180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // bits. 393280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(edx, Operand(edx)); 393380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, kQuietNaNHighBitsMask << 1); 393480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal) { 393580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(EQUAL != 1); 393680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ setcc(above_equal, eax); 393780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 393880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 3939257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label nan; 3940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &nan, Label::kNear); 394180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 394280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 394380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&nan); 394480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); 394580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 394680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 394780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 394880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 394980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_identical); 395080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 395180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 395280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Strict equality can quickly decide whether objects are equal. 395380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Non-strict object equality is slower, so it is handled later in the stub. 395480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal && strict_) { 395580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow; // Fallthrough label. 3956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_smis; 395780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If we're doing a strict equality comparison, we don't have to do 395880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // type conversion, so we generate code to do fast comparison for objects 395980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and oddballs. Non-smi numbers and strings still go through the usual 396080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // slow-case code. 396180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If either is a Smi (we know that not both are), then they can only 396280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // be equal if the other is a HeapNumber. If so, use the slow case. 396380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 396480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT_EQ(0, Smi::FromInt(0)); 396580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(kSmiTagMask)); 396680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(ecx, Operand(eax)); 396780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Operand(edx)); 3968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, ¬_smis, Label::kNear); 396980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // One operand is a smi. 397080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 397180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check whether the non-smi is a heap number. 397280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagMask == 1); 397380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx still holds eax & kSmiTag, which is either zero or one. 397480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(ecx), Immediate(0x01)); 397580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, edx); 397680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(ebx, Operand(eax)); 397780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(ebx, Operand(ecx)); // ebx holds either 0 or eax ^ edx. 397880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(ebx, Operand(eax)); 397980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // if eax was smi, ebx is now edx, else eax. 398080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 398180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the non-smi operand is a heap number. 398280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), 398344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(masm->isolate()->factory()->heap_number_map())); 398480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If heap number, handle it in the slow case. 398569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(equal, &slow, Label::kNear); 398680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return non-equal (ebx is not zero) 398780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, ebx); 398880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 398980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 399080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_smis); 399180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If either operand is a JSObject or an oddball value, then they are not 399280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // equal since their pointers are different 399380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // There is no test for undetectability in strict equality. 399480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 399580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the type of the first operand. 399680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the first object is a JS object, we have done pointer comparison. 3997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label first_non_object; 39983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); 39993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); 4000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, &first_non_object, Label::kNear); 400180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 400280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return non-zero (eax is not zero) 4003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label return_not_equal; 400480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kHeapObjectTag != 0); 400580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&return_not_equal); 400680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 400780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 400880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&first_non_object); 400980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for oddballs: true, false, null, undefined. 401080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpInstanceType(ecx, ODDBALL_TYPE); 401180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &return_not_equal); 401280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 40133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ecx); 401480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &return_not_equal); 401580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 401680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for oddballs: true, false, null, undefined. 401780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpInstanceType(ecx, ODDBALL_TYPE); 401880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &return_not_equal); 401980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 402080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fall through to the general case. 402180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 402280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 402380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 402480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Generate the number comparison code. 402580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (include_number_compare_) { 402680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_number_comparison; 402780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label unordered; 40288b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 402980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope use_sse2(SSE2); 403080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope use_cmov(CMOV); 403180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 403280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); 403380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ucomisd(xmm0, xmm1); 403480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 403580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Don't base result on EFLAGS when a NaN is involved. 403669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(parity_even, &unordered, Label::kNear); 403780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return a result of -1, 0, or 1, based on EFLAGS. 403880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, 0); // equal 403980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(Smi::FromInt(1))); 404080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmov(above, eax, Operand(ecx)); 404180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(Smi::FromInt(-1))); 404280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmov(below, eax, Operand(ecx)); 404380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 404480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 404580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FloatingPointHelper::CheckFloatOperands( 404680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen masm, &non_number_comparison, ebx); 404780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FloatingPointHelper::LoadFloatOperand(masm, eax); 404880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FloatingPointHelper::LoadFloatOperand(masm, edx); 404980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ FCmp(); 405080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 405180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Don't base result on EFLAGS when a NaN is involved. 405269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(parity_even, &unordered, Label::kNear); 405380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4054257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label below_label, above_label; 405580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return a result of -1, 0, or 1, based on EFLAGS. 405669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(below, &below_label, Label::kNear); 405769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(above, &above_label, Label::kNear); 405880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 40599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Set(eax, Immediate(0)); 406080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 406180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 406280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&below_label); 406380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(Smi::FromInt(-1))); 406480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 406580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 406680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&above_label); 406780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(Smi::FromInt(1))); 406880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 406980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 407080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 407180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If one of the numbers was NaN, then the result is always false. 407280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The cc is never not-equal. 407380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&unordered); 407480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(cc_ != not_equal); 407580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == less || cc_ == less_equal) { 407680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(Smi::FromInt(1))); 407780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 407880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(Smi::FromInt(-1))); 407980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 408080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 408180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 408280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The number comparison code did not provide a valid result. 408380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_number_comparison); 408480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 408580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 408680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fast negative check for symbol-to-symbol equality. 408780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label check_for_strings; 408880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal) { 408980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); 409080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); 409180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 409280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We've already checked for object identity, so if both operands 409380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // are symbols they aren't equal. Register eax already holds a 409480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // non-zero value, which indicates not equal, so just return. 409580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 409680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 409780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 409880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_for_strings); 409980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 410080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, 410180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &check_unequal_objects); 410280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 410380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Inline comparison of ascii strings. 4104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (cc_ == equal) { 4105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringCompareStub::GenerateFlatAsciiStringEquals(masm, 410680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen edx, 410780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen eax, 410880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ecx, 4109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ebx); 4110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 4111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringCompareStub::GenerateCompareFlatAsciiStrings(masm, 4112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch edx, 4113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch eax, 4114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ecx, 4115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ebx, 4116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch edi); 4117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 411880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG 411980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fall-through from string comparison"); 412080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 412180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 412280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_unequal_objects); 412380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal && !strict_) { 412480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Non-strict equality. Objects are unequal if 412580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // they are both JSObjects and not undetectable, 412680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and their pointers are different. 4127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_both_objects; 4128257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label return_unequal; 412980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // At most one is a smi, so we can test for smi by adding the two. 413080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // A smi plus a heap object has the low bit set, a heap object plus 413180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // a heap object has the low bit clear. 413280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 413380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagMask == 1); 413480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(eax, edx, times_1, 0)); 413580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Immediate(kSmiTagMask)); 4136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, ¬_both_objects, Label::kNear); 41373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); 4138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, ¬_both_objects, Label::kNear); 41393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx); 4140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, ¬_both_objects, Label::kNear); 414180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We do not bail out after this point. Both are JSObjects, and 414280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // they are equal if and only if both are undetectable. 414380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The and of the undetectable flags is 1 if and only if they are equal. 414480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 414580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1 << Map::kIsUndetectable); 4146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &return_unequal, Label::kNear); 414780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ebx, Map::kBitFieldOffset), 414880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1 << Map::kIsUndetectable); 4149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &return_unequal, Label::kNear); 415080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The objects are both undetectable, so they both compare as the value 415180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // undefined, and are equal. 415280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(EQUAL)); 415380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&return_unequal); 415480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return non-equal by returning the non-zero object pointer in eax, 415580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // or return equal if we fell through to here. 415680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); // rax, rdx were pushed 415780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_both_objects); 415880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 415980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 416080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Push arguments below the return address. 416180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ecx); 416280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(edx); 416380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(eax); 416480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 416580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Figure out which native to call and setup the arguments. 416680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Builtins::JavaScript builtin; 416780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal) { 416880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; 416980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 417080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen builtin = Builtins::COMPARE; 417180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); 417280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 417380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 417480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore return address on the stack. 417580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ecx); 417680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 417780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) 417880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // tagged as a small integer. 417980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ InvokeBuiltin(builtin, JUMP_FUNCTION); 418080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 418180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 418280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 418380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::BranchIfNonSymbol(MacroAssembler* masm, 418480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* label, 418580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register object, 418680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 41873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(object, label); 418880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset)); 418980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); 419080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(scratch, kIsSymbolMask | kIsNotStringMask); 419180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(scratch, kSymbolTag | kStringTag); 419280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, label); 419380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 419480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 419580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 419680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StackCheckStub::Generate(MacroAssembler* masm) { 4197f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch __ TailCallRuntime(Runtime::kStackGuard, 0, 1); 419880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 419980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 420080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 420180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CallFunctionStub::Generate(MacroAssembler* masm) { 4202589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Label slow, non_function; 420380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // The receiver might implicitly be the global object. This is 4205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // indicated by passing the hole as the receiver to the call 4206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // function stub. 4207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (ReceiverMightBeImplicit()) { 4208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label call; 420980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the receiver from the stack. 421080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // +1 ~ return address 421180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, (argc_ + 1) * kPointerSize)); 4212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Call as function is indicated with the hole. 4213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(eax, masm->isolate()->factory()->the_hole_value()); 4214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &call, Label::kNear); 4215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Patch the receiver on the stack with the global receiver object. 4216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ebx, GlobalObjectOperand()); 4217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); 4218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(Operand(esp, (argc_ + 1) * kPointerSize), ebx); 4219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call); 422080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 422180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 422280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the function to call from the stack. 422380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // +2 ~ receiver, return address 422480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, Operand(esp, (argc_ + 2) * kPointerSize)); 422580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 422680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the function really is a JavaScript function. 4227589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ JumpIfSmi(edi, &non_function); 422880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Goto slow case if we do not have a function. 422980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 4230257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &slow); 423180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 423280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fast-case: Just invoke the function. 423380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ParameterCount actual(argc_); 4234257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 4235257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (ReceiverMightBeImplicit()) { 4236257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label call_as_function; 4237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(eax, masm->isolate()->factory()->the_hole_value()); 4238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &call_as_function); 4239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeFunction(edi, 4240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch actual, 4241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch JUMP_FUNCTION, 4242257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch NullCallWrapper(), 4243257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CALL_AS_METHOD); 4244257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_as_function); 4245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 4246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeFunction(edi, 4247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch actual, 4248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch JUMP_FUNCTION, 4249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch NullCallWrapper(), 4250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CALL_AS_FUNCTION); 425180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 425280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case: Non-function called. 425380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 4254589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // Check for function proxy. 4255589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); 4256589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ j(not_equal, &non_function); 4257589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ pop(ecx); 4258589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ push(edi); // put proxy as additional argument under return address 4259589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ push(ecx); 4260589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ Set(eax, Immediate(argc_ + 1)); 4261589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ Set(ebx, Immediate(0)); 4262589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ SetCallKind(ecx, CALL_AS_FUNCTION); 4263589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); 4264589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch { 4265589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Handle<Code> adaptor = 4266589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); 4267589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ jmp(adaptor, RelocInfo::CODE_TARGET); 4268589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch } 4269589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 427080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // CALL_NON_FUNCTION expects the non-function callee as receiver (instead 427180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // of the original receiver from the call site). 4272589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ bind(&non_function); 427380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi); 427480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(argc_)); 427580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(ebx, Immediate(0)); 4276589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ SetCallKind(ecx, CALL_AS_METHOD); 427780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); 427844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Handle<Code> adaptor = 427944f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); 428080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(adaptor, RelocInfo::CODE_TARGET); 428180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 428280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 428380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 428444f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool CEntryStub::NeedsImmovableCode() { 428544f0eee88ff00398ff7f715fab053374d808c90dSteve Block return false; 428644f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 428744f0eee88ff00398ff7f715fab053374d808c90dSteve Block 428844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 428980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { 4290e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Throw(eax); 429180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 429280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 429380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 429480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateCore(MacroAssembler* masm, 429580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_normal_exception, 429680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_termination_exception, 429780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_out_of_memory_exception, 429880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool do_gc, 42991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block bool always_allocate_scope) { 430080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result parameter for PerformGC, if any 430180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: pointer to C function (C callee-saved) 430280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebp: frame pointer (restored after C call) 430380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp: stack pointer (restored after C call) 430480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: number of arguments including receiver (C callee-saved) 430580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: pointer to the first argument (C callee-saved) 430680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 430780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result returned in eax, or eax+edx if result_size_ is 2. 430880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 430980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check stack alignment. 431080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 431180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CheckStackAlignment(); 431280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 431380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 431480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (do_gc) { 431580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Pass failure code returned from last attempt as first argument to 431680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the 431780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stack alignment is known to be correct. This function takes one argument 431880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // which is passed on the stack, and we know that the stack has been 431980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // prepared to pass at least one argument. 432080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 0 * kPointerSize), eax); // Result. 432180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY); 432280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 432380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 432480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference scope_depth = 432544f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::heap_always_allocate_scope_depth(masm->isolate()); 432680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (always_allocate_scope) { 432780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ inc(Operand::StaticVariable(scope_depth)); 432880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 432980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 433080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call C function. 433180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 0 * kPointerSize), edi); // argc. 433280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 1 * kPointerSize), esi); // argv. 433344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(Operand(esp, 2 * kPointerSize), 433444f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(ExternalReference::isolate_address())); 433580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ call(Operand(ebx)); 433680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is in eax or edx:eax - do not destroy these registers! 433780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 433880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (always_allocate_scope) { 433980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ dec(Operand::StaticVariable(scope_depth)); 434080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 434180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 434280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure we're not trying to return 'the hole' from the runtime 434380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // call as this may lead to crashes in the IC code later. 434480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 4345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label okay; 434644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, masm->isolate()->factory()->the_hole_value()); 4347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &okay, Label::kNear); 434880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ int3(); 434980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&okay); 435080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 435180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 435280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for failure result. 435380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label failure_returned; 435480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); 435580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(eax, 1)); 435680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Lower 2 bits of ecx are 0 iff eax has failure tag. 435780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Immediate(kFailureTagMask)); 4358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &failure_returned); 435980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 436044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference pending_exception_address( 4361589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Isolate::kPendingExceptionAddress, masm->isolate()); 43621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 43631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check that there is no pending exception, otherwise we 43641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // should have returned some failure value. 43651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (FLAG_debug_code) { 43661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(edx); 43671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(edx, Operand::StaticVariable( 436844f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::the_hole_value_location(masm->isolate()))); 4369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label okay; 43701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ cmp(edx, Operand::StaticVariable(pending_exception_address)); 43711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Cannot use check here as it attempts to generate call into runtime. 4372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &okay, Label::kNear); 43731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ int3(); 43741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&okay); 43751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ pop(edx); 43761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 43771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 437880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Exit the JavaScript to C++ exit frame. 4379b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ LeaveExitFrame(save_doubles_); 438080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 438180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 438280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handling of failure. 438380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&failure_returned); 438480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 438580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label retry; 438680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the returned exception is RETRY_AFTER_GC continue at retry label 438780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); 438880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); 438969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &retry, Label::kNear); 439080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 439180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Special handling of out of memory exceptions. 439280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException())); 439380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, throw_out_of_memory_exception); 439480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 439580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Retrieve the pending exception and clear the variable. 439644f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference the_hole_location = 439744f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::the_hole_value_location(masm->isolate()); 439880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand::StaticVariable(pending_exception_address)); 439944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(edx, Operand::StaticVariable(the_hole_location)); 440080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(pending_exception_address), edx); 440180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 440280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Special handling of termination exceptions which are uncatchable 440380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // by javascript code. 440444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, masm->isolate()->factory()->termination_exception()); 440580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, throw_termination_exception); 440680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 440780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle normal exception. 440880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(throw_normal_exception); 440980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 441080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Retry. 441180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&retry); 441280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 441380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 441480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 441580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, 441680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen UncatchableExceptionType type) { 4417e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ThrowUncatchable(type, eax); 441880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 441980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 442080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 442180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::Generate(MacroAssembler* masm) { 442280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: number of arguments including receiver 442380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: pointer to C function (C callee-saved) 442480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebp: frame pointer (restored after C call) 442580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp: stack pointer (restored after C call) 442680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: current context (C callee-saved) 442780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: JS function of the caller (C callee-saved) 442880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 442980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NOTE: Invocations of builtins may return failure objects instead 443080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // of a proper result. The builtin entry handles this by performing 443180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // a garbage collection and retrying the builtin (twice). 443280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 443380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Enter the exit frame that transitions from JavaScript to C++. 4434b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ EnterExitFrame(save_doubles_); 443580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 443680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result parameter for PerformGC, if any (setup below) 443780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: pointer to builtin function (C callee-saved) 443880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebp: frame pointer (restored after C call) 443980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp: stack pointer (restored after C call) 444080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: number of arguments including receiver (C callee-saved) 444180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: argv pointer (C callee-saved) 444280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 444380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_normal_exception; 444480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_termination_exception; 444580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_out_of_memory_exception; 444680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 444780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call into the runtime system. 444880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 444980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 445080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 445180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 445280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen false, 445380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen false); 445480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 445580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do space-specific GC and retry runtime call. 445680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 445780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 445880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 445980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 446080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen true, 446180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen false); 446280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 446380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do full GC and retry runtime call one final time. 446480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Failure* failure = Failure::InternalError(); 446580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure))); 446680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 446780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 446880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 446980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 447080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen true, 447180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen true); 447280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 447380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_out_of_memory_exception); 447480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateThrowUncatchable(masm, OUT_OF_MEMORY); 447580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 447680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_termination_exception); 447780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateThrowUncatchable(masm, TERMINATION); 447880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 447980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_normal_exception); 448080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateThrowTOS(masm); 448180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 448280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 448380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 448480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { 448580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label invoke, exit; 448680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label not_outermost_js, not_outermost_js_2; 448780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 448880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Setup frame. 448980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ebp); 449080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebp, Operand(esp)); 449180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 449280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Push marker in two places. 449380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; 449480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Immediate(Smi::FromInt(marker))); // context slot 449580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Immediate(Smi::FromInt(marker))); // function slot 449680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Save callee-saved registers (C calling conventions). 449780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(edi); 449880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(esi); 449980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ebx); 450080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 450180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Save copies of the top frame descriptor on the stack. 4502589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, masm->isolate()); 450380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Operand::StaticVariable(c_entry_fp)); 450480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 450580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If this is the outermost JS call, set js_entry_sp value. 4506589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, 450744f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 450880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0)); 450969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_equal, ¬_outermost_js, Label::kNear); 451080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(js_entry_sp), ebp); 4511053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); 4512053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block Label cont; 451369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&cont, Label::kNear); 451480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_outermost_js); 4515053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME))); 4516053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ bind(&cont); 451780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 451880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call a faked try-block that does the invoke. 451980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ call(&invoke); 452080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 452180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Caught exception: Store result (exception) in the pending 452280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // exception field in the JSEnv and return a failure sentinel. 4523589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch ExternalReference pending_exception(Isolate::kPendingExceptionAddress, 452444f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 452580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(pending_exception), eax); 452680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception())); 452780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&exit); 452880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 452980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Invoke: Link this frame into the handler chain. 453080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&invoke); 453180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); 453280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 453380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Clear any pending exceptions. 453444f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference the_hole_location = 453544f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::the_hole_value_location(masm->isolate()); 453644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(edx, Operand::StaticVariable(the_hole_location)); 453780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(pending_exception), edx); 453880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 453980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fake a receiver (NULL). 454080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Immediate(0)); // receiver 454180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 454280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Invoke the function by calling through JS entry trampoline 454380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // builtin and pop the faked function when we return. Notice that we 454480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // cannot store a reference to the trampoline code directly in this 454580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stub, because the builtin stubs may not have been generated yet. 454680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (is_construct) { 454744f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference construct_entry( 454844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Builtins::kJSConstructEntryTrampoline, 454944f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 455080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Immediate(construct_entry)); 455180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 455244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference entry(Builtins::kJSEntryTrampoline, 455344f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 455480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Immediate(entry)); 455580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 455680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(edx, 0)); // deref address 455780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); 455880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ call(Operand(edx)); 455980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 456080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Unlink this frame from the handler chain. 4561053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ PopTryHandler(); 456280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4563053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ bind(&exit); 4564053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block // Check if the current stack frame is marked as the outermost JS frame. 4565053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ pop(ebx); 4566053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ cmp(Operand(ebx), 4567053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); 456880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, ¬_outermost_js_2); 456980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0)); 457080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_outermost_js_2); 457180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 457280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore the top frame descriptor from the stack. 457344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ pop(Operand::StaticVariable(ExternalReference( 4574589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Isolate::kCEntryFPAddress, 457544f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()))); 457680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 457780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore callee-saved registers (C calling conventions). 457880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ebx); 457980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(esi); 458080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(edi); 458180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(esp), Immediate(2 * kPointerSize)); // remove markers 458280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 458380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore frame pointer and return. 458480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ebp); 458580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 458680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 458780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 458880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4589086aeeaae12517475c22695a200be45495516549Ben Murdoch// Generate stub code for instanceof. 4590086aeeaae12517475c22695a200be45495516549Ben Murdoch// This code can patch a call site inlined cache of the instance of check, 4591086aeeaae12517475c22695a200be45495516549Ben Murdoch// which looks like this. 4592086aeeaae12517475c22695a200be45495516549Ben Murdoch// 4593086aeeaae12517475c22695a200be45495516549Ben Murdoch// 81 ff XX XX XX XX cmp edi, <the hole, patched to a map> 4594086aeeaae12517475c22695a200be45495516549Ben Murdoch// 75 0a jne <some near label> 4595086aeeaae12517475c22695a200be45495516549Ben Murdoch// b8 XX XX XX XX mov eax, <the hole, patched to either true or false> 4596086aeeaae12517475c22695a200be45495516549Ben Murdoch// 4597086aeeaae12517475c22695a200be45495516549Ben Murdoch// If call site patching is requested the stack will have the delta from the 4598086aeeaae12517475c22695a200be45495516549Ben Murdoch// return address to the cmp instruction just below the return address. This 4599086aeeaae12517475c22695a200be45495516549Ben Murdoch// also means that call site patching can only take place with arguments in 4600086aeeaae12517475c22695a200be45495516549Ben Murdoch// registers. TOS looks like this when call site patching is requested 4601086aeeaae12517475c22695a200be45495516549Ben Murdoch// 4602086aeeaae12517475c22695a200be45495516549Ben Murdoch// esp[0] : return address 4603086aeeaae12517475c22695a200be45495516549Ben Murdoch// esp[4] : delta from return address to cmp instruction 4604086aeeaae12517475c22695a200be45495516549Ben Murdoch// 460580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid InstanceofStub::Generate(MacroAssembler* masm) { 4606086aeeaae12517475c22695a200be45495516549Ben Murdoch // Call site inlining and patching implies arguments in registers. 4607086aeeaae12517475c22695a200be45495516549Ben Murdoch ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck()); 4608086aeeaae12517475c22695a200be45495516549Ben Murdoch 4609b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fixed register usage throughout the stub. 4610b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register object = eax; // Object (lhs). 4611b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register map = ebx; // Map of the object. 4612b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register function = edx; // Function (rhs). 4613b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register prototype = edi; // Prototype of the function. 4614b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register scratch = ecx; 4615b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4616086aeeaae12517475c22695a200be45495516549Ben Murdoch // Constants describing the call site code to patch. 4617086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int kDeltaToCmpImmediate = 2; 4618086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int kDeltaToMov = 8; 4619086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int kDeltaToMovImmediate = 9; 4620086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int8_t kCmpEdiImmediateByte1 = BitCast<int8_t, uint8_t>(0x81); 4621086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int8_t kCmpEdiImmediateByte2 = BitCast<int8_t, uint8_t>(0xff); 4622086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8); 4623086aeeaae12517475c22695a200be45495516549Ben Murdoch 462444f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference roots_address = 462544f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::roots_address(masm->isolate()); 4626086aeeaae12517475c22695a200be45495516549Ben Murdoch 4627086aeeaae12517475c22695a200be45495516549Ben Murdoch ASSERT_EQ(object.code(), InstanceofStub::left().code()); 4628086aeeaae12517475c22695a200be45495516549Ben Murdoch ASSERT_EQ(function.code(), InstanceofStub::right().code()); 4629086aeeaae12517475c22695a200be45495516549Ben Murdoch 4630b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Get the object and function - they are always both needed. 4631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label slow, not_js_object; 4632086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasArgsInRegisters()) { 4633b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(object, Operand(esp, 2 * kPointerSize)); 4634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(function, Operand(esp, 1 * kPointerSize)); 4635b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 463680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 463780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the left hand is a JS object. 46383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(object, ¬_js_object); 4639b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); 464080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4641086aeeaae12517475c22695a200be45495516549Ben Murdoch // If there is a call site cache don't look in the global cache, but do the 4642086aeeaae12517475c22695a200be45495516549Ben Murdoch // real lookup and update the call site cache. 4643086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasCallSiteInlineCheck()) { 4644086aeeaae12517475c22695a200be45495516549Ben Murdoch // Look up the function and the map in the instanceof cache. 4645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 4646086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); 4647086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmp(function, 4648086aeeaae12517475c22695a200be45495516549Ben Murdoch Operand::StaticArray(scratch, times_pointer_size, roots_address)); 4649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 4650086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); 4651086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmp(map, Operand::StaticArray( 4652086aeeaae12517475c22695a200be45495516549Ben Murdoch scratch, times_pointer_size, roots_address)); 4653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 4654086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); 4655086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(eax, Operand::StaticArray( 4656086aeeaae12517475c22695a200be45495516549Ben Murdoch scratch, times_pointer_size, roots_address)); 4657086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 4658086aeeaae12517475c22695a200be45495516549Ben Murdoch __ bind(&miss); 4659086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4660086aeeaae12517475c22695a200be45495516549Ben Murdoch 4661b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Get the prototype of the function. 4662b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TryGetFunctionPrototype(function, prototype, scratch, &slow); 466380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 466480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the function prototype is a JS object. 46653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(prototype, &slow); 4666b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); 4667b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4668086aeeaae12517475c22695a200be45495516549Ben Murdoch // Update the global instanceof or call site inlined cache with the current 4669086aeeaae12517475c22695a200be45495516549Ben Murdoch // map and function. The cached answer will be set when it is known below. 4670086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasCallSiteInlineCheck()) { 4671b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); 4672b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), map); 4673b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); 4674b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), 4675b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch function); 4676086aeeaae12517475c22695a200be45495516549Ben Murdoch } else { 4677086aeeaae12517475c22695a200be45495516549Ben Murdoch // The constants for the code patching are based on no push instructions 4678086aeeaae12517475c22695a200be45495516549Ben Murdoch // at the call site. 4679086aeeaae12517475c22695a200be45495516549Ben Murdoch ASSERT(HasArgsInRegisters()); 4680086aeeaae12517475c22695a200be45495516549Ben Murdoch // Get return address and delta to inlined map check. 4681086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Operand(esp, 0 * kPointerSize)); 4682086aeeaae12517475c22695a200be45495516549Ben Murdoch __ sub(scratch, Operand(esp, 1 * kPointerSize)); 4683086aeeaae12517475c22695a200be45495516549Ben Murdoch if (FLAG_debug_code) { 4684086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmpb(Operand(scratch, 0), kCmpEdiImmediateByte1); 4685086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 1)"); 4686086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmpb(Operand(scratch, 1), kCmpEdiImmediateByte2); 4687086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 2)"); 4688086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4689086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(Operand(scratch, kDeltaToCmpImmediate), map); 4690086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4691b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4692b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Loop through the prototype chain of the object looking for the function 4693b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // prototype. 4694b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset)); 4695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop, is_instance, is_not_instance; 469680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 4697b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(scratch, Operand(prototype)); 4698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &is_instance, Label::kNear); 469944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 470044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(Operand(scratch), Immediate(factory->null_value())); 4701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &is_not_instance, Label::kNear); 4702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); 4703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); 470480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&loop); 470580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 470680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&is_instance); 4707086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasCallSiteInlineCheck()) { 4708086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Set(eax, Immediate(0)); 4709086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); 4710086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(Operand::StaticArray(scratch, 4711086aeeaae12517475c22695a200be45495516549Ben Murdoch times_pointer_size, roots_address), eax); 4712086aeeaae12517475c22695a200be45495516549Ben Murdoch } else { 4713086aeeaae12517475c22695a200be45495516549Ben Murdoch // Get return address and delta to inlined map check. 471444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, factory->true_value()); 4715086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Operand(esp, 0 * kPointerSize)); 4716086aeeaae12517475c22695a200be45495516549Ben Murdoch __ sub(scratch, Operand(esp, 1 * kPointerSize)); 4717086aeeaae12517475c22695a200be45495516549Ben Murdoch if (FLAG_debug_code) { 4718086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); 4719086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); 4720086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4721086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(Operand(scratch, kDeltaToMovImmediate), eax); 4722086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!ReturnTrueFalseObject()) { 4723086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Set(eax, Immediate(0)); 4724086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4725086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4726086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 472780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 472880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&is_not_instance); 4729086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasCallSiteInlineCheck()) { 4730086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 4731086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); 4732086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(Operand::StaticArray( 4733086aeeaae12517475c22695a200be45495516549Ben Murdoch scratch, times_pointer_size, roots_address), eax); 4734086aeeaae12517475c22695a200be45495516549Ben Murdoch } else { 4735086aeeaae12517475c22695a200be45495516549Ben Murdoch // Get return address and delta to inlined map check. 473644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, factory->false_value()); 4737086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Operand(esp, 0 * kPointerSize)); 4738086aeeaae12517475c22695a200be45495516549Ben Murdoch __ sub(scratch, Operand(esp, 1 * kPointerSize)); 4739086aeeaae12517475c22695a200be45495516549Ben Murdoch if (FLAG_debug_code) { 4740086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); 4741086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); 4742086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4743086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(Operand(scratch, kDeltaToMovImmediate), eax); 4744086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!ReturnTrueFalseObject()) { 4745086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 4746086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4747086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4748086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 4749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label object_not_null, object_not_null_or_smi; 4751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_js_object); 4752b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Before null, smi and string value checks, check that the rhs is a function 4753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // as for a non-function rhs an exception needs to be thrown. 475469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfSmi(function, &slow, Label::kNear); 4755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); 475669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_equal, &slow, Label::kNear); 4757b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Null is not instance of anything. 475944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(object, factory->null_value()); 476069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_equal, &object_not_null, Label::kNear); 4761b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 4762086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 4763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&object_not_null); 4765b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Smi values is not instance of anything. 476669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfNotSmi(object, &object_not_null_or_smi, Label::kNear); 4767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 4768086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 4769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&object_not_null_or_smi); 4771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // String values is not instance of anything. 4772b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Condition is_string = masm->IsObjectStringType(object, scratch, scratch); 477369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(NegateCondition(is_string), &slow, Label::kNear); 4774b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 4775086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 477680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 477780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case: Go through the JavaScript implementation. 477880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 4779086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!ReturnTrueFalseObject()) { 4780086aeeaae12517475c22695a200be45495516549Ben Murdoch // Tail call the builtin which returns 0 or 1. 4781086aeeaae12517475c22695a200be45495516549Ben Murdoch if (HasArgsInRegisters()) { 4782086aeeaae12517475c22695a200be45495516549Ben Murdoch // Push arguments below return address. 4783086aeeaae12517475c22695a200be45495516549Ben Murdoch __ pop(scratch); 4784086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(object); 4785086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(function); 4786086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(scratch); 4787086aeeaae12517475c22695a200be45495516549Ben Murdoch } 4788086aeeaae12517475c22695a200be45495516549Ben Murdoch __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 4789086aeeaae12517475c22695a200be45495516549Ben Murdoch } else { 4790086aeeaae12517475c22695a200be45495516549Ben Murdoch // Call the builtin and convert 0/1 to true/false. 4791086aeeaae12517475c22695a200be45495516549Ben Murdoch __ EnterInternalFrame(); 4792b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(object); 4793b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(function); 4794086aeeaae12517475c22695a200be45495516549Ben Murdoch __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); 4795086aeeaae12517475c22695a200be45495516549Ben Murdoch __ LeaveInternalFrame(); 4796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label true_value, done; 4797086aeeaae12517475c22695a200be45495516549Ben Murdoch __ test(eax, Operand(eax)); 4798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &true_value, Label::kNear); 479944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, factory->false_value()); 4800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 4801086aeeaae12517475c22695a200be45495516549Ben Murdoch __ bind(&true_value); 480244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, factory->true_value()); 4803086aeeaae12517475c22695a200be45495516549Ben Murdoch __ bind(&done); 4804086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 4805b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 480680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 480780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 480880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4809086aeeaae12517475c22695a200be45495516549Ben MurdochRegister InstanceofStub::left() { return eax; } 4810086aeeaae12517475c22695a200be45495516549Ben Murdoch 4811086aeeaae12517475c22695a200be45495516549Ben Murdoch 4812086aeeaae12517475c22695a200be45495516549Ben MurdochRegister InstanceofStub::right() { return edx; } 4813086aeeaae12517475c22695a200be45495516549Ben Murdoch 4814086aeeaae12517475c22695a200be45495516549Ben Murdoch 481580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenint CompareStub::MinorKey() { 481680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Encode the three parameters in a unique 16 bit value. To avoid duplicate 481780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stubs the never NaN NaN condition is only taken into account if the 481880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // condition is equals. 481980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(static_cast<unsigned>(cc_) < (1 << 12)); 482080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 482180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return ConditionField::encode(static_cast<unsigned>(cc_)) 482280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | RegisterField::encode(false) // lhs_ and rhs_ are not used 482380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | StrictField::encode(strict_) 482480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) 48250d5e116f6aee03185f237311a943491bb079a768Kristian Monsen | IncludeNumberCompareField::encode(include_number_compare_) 48260d5e116f6aee03185f237311a943491bb079a768Kristian Monsen | IncludeSmiCompareField::encode(include_smi_compare_); 482780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 482880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 482980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 483080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Unfortunately you have to run without snapshots to see most of these 483180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// names in the profile since most compare stubs end up in the snapshot. 48323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid CompareStub::PrintName(StringStream* stream) { 483380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 483480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const char* cc_name; 483580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen switch (cc_) { 483680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case less: cc_name = "LT"; break; 483780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case greater: cc_name = "GT"; break; 483880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case less_equal: cc_name = "LE"; break; 483980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case greater_equal: cc_name = "GE"; break; 484080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case equal: cc_name = "EQ"; break; 484180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case not_equal: cc_name = "NE"; break; 484280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen default: cc_name = "UnknownCondition"; break; 484380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 48443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch bool is_equality = cc_ == equal || cc_ == not_equal; 48453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("CompareStub_%s", cc_name); 48463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (strict_ && is_equality) stream->Add("_STRICT"); 48473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN"); 48483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (!include_number_compare_) stream->Add("_NO_NUMBER"); 48493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (!include_smi_compare_) stream->Add("_NO_SMI"); 485080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 485180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 485280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 485380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// ------------------------------------------------------------------------- 485480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharCodeAtGenerator 485580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 485680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { 485780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label flat_string; 485880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label ascii_string; 485980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label got_char_code; 486069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label sliced_string; 486180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 486280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the receiver is a smi trigger the non-string case. 486380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 48643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(object_, receiver_not_string_); 486580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 486680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fetch the instance type of the receiver into result register. 486780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); 486880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); 486980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the receiver is not a string trigger the non-string case. 487080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(result_, Immediate(kIsNotStringMask)); 487180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, receiver_not_string_); 487280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 487380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the index is non-smi trigger the non-smi case. 487480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 48753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(index_, &index_not_smi_); 487680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 487780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Put smi-tagged index into scratch register. 487880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch_, index_); 487980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&got_smi_index_); 488080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 488180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for index out of range. 488280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(scratch_, FieldOperand(object_, String::kLengthOffset)); 488380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, index_out_of_range_); 488480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 488580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We need special handling for non-flat strings. 488680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSeqStringTag == 0); 488780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(result_, Immediate(kStringRepresentationMask)); 488880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &flat_string); 488980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 489080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle non-flat strings. 489169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ and_(result_, kStringRepresentationMask); 489269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kConsStringTag < kExternalStringTag); 489369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); 489469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(result_, kExternalStringTag); 489569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(greater, &sliced_string, Label::kNear); 489669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(equal, &call_runtime_); 489780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 489880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ConsString. 489980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check whether the right hand side is the empty string (i.e. if 490080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // this is really a flat string in a cons string). If that is not 490180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the case we would rather go to the runtime system now to flatten 490280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the string. 490369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label assure_seq_string; 490480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(object_, ConsString::kSecondOffset), 490544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(masm->isolate()->factory()->empty_string())); 490680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &call_runtime_); 490780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the first of the two strings and load its instance type. 490880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(object_, FieldOperand(object_, ConsString::kFirstOffset)); 490969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&assure_seq_string, Label::kNear); 491069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 491169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // SlicedString, unpack and add offset. 491269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&sliced_string); 491369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ add(scratch_, FieldOperand(object_, SlicedString::kOffsetOffset)); 491469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(object_, FieldOperand(object_, SlicedString::kParentOffset)); 491569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 491669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Assure that we are dealing with a sequential string. Go to runtime if not. 491769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&assure_seq_string); 491880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); 491980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); 492080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSeqStringTag == 0); 492180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(result_, Immediate(kStringRepresentationMask)); 492280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &call_runtime_); 492369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&flat_string, Label::kNear); 492480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 492580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for 1-byte or 2-byte string. 492680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&flat_string); 4927589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 4928589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 492980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(result_, Immediate(kStringEncodingMask)); 493069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_zero, &ascii_string, Label::kNear); 493180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 493280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // 2-byte string. 493380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the 2-byte character code into the result register. 493480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); 493580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_w(result_, FieldOperand(object_, 493680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch_, times_1, // Scratch is smi-tagged. 493780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SeqTwoByteString::kHeaderSize)); 493869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&got_char_code, Label::kNear); 493980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 494080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ASCII string. 494180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the byte into the result register. 494280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&ascii_string); 494380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch_); 494480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(result_, FieldOperand(object_, 494580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch_, times_1, 494680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SeqAsciiString::kHeaderSize)); 494780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&got_char_code); 494880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(result_); 494980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&exit_); 495080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 495180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 495280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 495380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateSlow( 495480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen MacroAssembler* masm, const RuntimeCallHelper& call_helper) { 495580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough to CharCodeAt slow case"); 495680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 495780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Index is not a smi. 495880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&index_not_smi_); 495980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If index is a heap number, try converting it to an integer. 496044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CheckMap(index_, 496144f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()->factory()->heap_number_map(), 496244f0eee88ff00398ff7f715fab053374d808c90dSteve Block index_not_number_, 4963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch DONT_DO_SMI_CHECK); 496480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 496580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(object_); 496680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(index_); 496780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(index_); // Consumed by runtime conversion function. 496880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (index_flags_ == STRING_INDEX_IS_NUMBER) { 496980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); 497080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 497180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); 497280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NumberToSmi discards numbers that are not exact integers. 497380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kNumberToSmi, 1); 497480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 497580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!scratch_.is(eax)) { 497680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Save the conversion result before the pop instructions below 497780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // have a chance to overwrite it. 497880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch_, eax); 497980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 498080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(index_); 498180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(object_); 498280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Reload the instance type. 498380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); 498480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); 498580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 498680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If index is still not a smi, it must be out of range. 498780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 49883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(scratch_, index_out_of_range_); 498980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Otherwise, return to the fast path. 499080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&got_smi_index_); 499180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 499280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call runtime. We get here when the receiver is a string and the 499380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // index is a number, but the code of getting the actual character 499480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // is too complex (e.g., when the string needs to be flattened). 499580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&call_runtime_); 499680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 499780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(object_); 499880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(index_); 499980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kStringCharCodeAt, 2); 500080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!result_.is(eax)) { 500180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, eax); 500280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 500380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 500480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&exit_); 500580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 500680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough from CharCodeAt slow case"); 500780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 500880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 500980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 501080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// ------------------------------------------------------------------------- 501180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharFromCodeGenerator 501280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 501380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { 501480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fast case of Heap::LookupSingleCharacterStringFromCode. 501580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 501680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiShiftSize == 0); 501780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); 501880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(code_, 501980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(kSmiTagMask | 502080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ((~String::kMaxAsciiCharCode) << kSmiTagSize))); 5021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &slow_case_); 502280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 502344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 502444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Set(result_, Immediate(factory->single_character_string_cache())); 502580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 502680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize == 1); 502780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiShiftSize == 0); 502880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // At this point code register contains smi tagged ascii char code. 502980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, FieldOperand(result_, 503080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen code_, times_half_pointer_size, 503180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize)); 503244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(result_, factory->undefined_value()); 5033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &slow_case_); 503480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&exit_); 503580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 503680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 503780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 503880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateSlow( 503980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen MacroAssembler* masm, const RuntimeCallHelper& call_helper) { 504080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough to CharFromCode slow case"); 504180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 504280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow_case_); 504380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 504480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(code_); 504580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kCharFromCode, 1); 504680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!result_.is(eax)) { 504780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, eax); 504880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 504980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 505080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&exit_); 505180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 505280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough from CharFromCode slow case"); 505380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 505480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 505580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 505680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// ------------------------------------------------------------------------- 505780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharAtGenerator 505880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 505980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateFast(MacroAssembler* masm) { 506080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_code_at_generator_.GenerateFast(masm); 506180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_from_code_generator_.GenerateFast(masm); 506280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 506380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 506480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 506580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateSlow( 506680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen MacroAssembler* masm, const RuntimeCallHelper& call_helper) { 506780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_code_at_generator_.GenerateSlow(masm, call_helper); 506880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_from_code_generator_.GenerateSlow(masm, call_helper); 506980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 507080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 507180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 507280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringAddStub::Generate(MacroAssembler* masm) { 50739ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label string_add_runtime, call_builtin; 50749ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Builtins::JavaScript builtin_id = Builtins::ADD; 507580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 507680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the two arguments. 507780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. 507880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. 507980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 508080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure that both arguments are strings if not known in advance. 50819ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick if (flags_ == NO_STRING_ADD_FLAGS) { 50823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &string_add_runtime); 508380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx); 508480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &string_add_runtime); 508580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 508680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // First argument is a a string, test second. 50873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(edx, &string_add_runtime); 508880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); 508980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &string_add_runtime); 50909ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick } else { 50919ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Here at least one of the arguments is definitely a string. 50929ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // We convert the one that is not known to be a string. 50939ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { 50949ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); 50959ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi, 50969ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick &call_builtin); 50979ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick builtin_id = Builtins::STRING_ADD_RIGHT; 50989ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { 50999ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); 51009ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick GenerateConvertArgument(masm, 1 * kPointerSize, edx, ebx, ecx, edi, 51019ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick &call_builtin); 51029ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick builtin_id = Builtins::STRING_ADD_LEFT; 51039ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick } 510480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 510580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 510680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both arguments are strings. 510780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first string 510880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: second string 510980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if either of the strings are empty. In that case return the other. 5110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label second_not_zero_length, both_not_zero_length; 511180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); 511280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 511380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Operand(ecx)); 5114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &second_not_zero_length, Label::kNear); 511580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Second string is empty, result is first string which is already in eax. 511644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 511744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 511880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 511980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&second_not_zero_length); 512080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); 512180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 512280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ebx, Operand(ebx)); 5123257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &both_not_zero_length, Label::kNear); 512480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // First string is empty, result is second string which is in edx. 512580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, edx); 512644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 512780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 512880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 512980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both strings are non-empty. 513080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first string 513180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: length of first string as a smi 513280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: length of second string as a smi 513380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: second string 513480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Look at the length of the result of adding the two strings. 513580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label string_add_flat_result, longer_than_two; 513680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&both_not_zero_length); 513780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(ebx, Operand(ecx)); 513880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength); 513980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle exceptionally long strings in the runtime system. 514080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(overflow, &string_add_runtime); 514144f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Use the symbol table when adding two one character strings, as it 514244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // helps later optimizations to return a symbol here. 514380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand(ebx), Immediate(Smi::FromInt(2))); 514480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &longer_than_two); 514580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 514680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that both strings are non-external ascii strings. 514780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, 514880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &string_add_runtime); 514980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 51509ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Get the two characters forming the new string. 515180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); 515280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); 515380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 515480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try to lookup two character string in symbol table. If it is not found 515580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // just allocate a new one. 51569ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label make_two_character_string, make_two_character_string_no_reload; 515780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateTwoCharacterSymbolTableProbe( 51589ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick masm, ebx, ecx, eax, edx, edi, 51599ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick &make_two_character_string_no_reload, &make_two_character_string); 516044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 516180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 516280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 51639ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Allocate a two character string. 516480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&make_two_character_string); 51659ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Reload the arguments. 51669ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. 51679ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. 51689ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Get the two characters forming the new string. 51699ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); 51709ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); 51719ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(&make_two_character_string_no_reload); 517244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_make_two_char(), 1); 51739ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ AllocateAsciiString(eax, // Result. 51749ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 2, // Length. 51759ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick edi, // Scratch 1. 51769ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick edx, // Scratch 2. 51779ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick &string_add_runtime); 51789ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Pack both characters in ebx. 51799ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ shl(ecx, kBitsPerByte); 51809ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ or_(ebx, Operand(ecx)); 51819ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Set the characters in the new string. 51829ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx); 518344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 51849ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ ret(2 * kPointerSize); 518580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 518680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&longer_than_two); 518780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if resulting string will be flat. 518880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand(ebx), Immediate(Smi::FromInt(String::kMinNonFlatLength))); 518980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(below, &string_add_flat_result); 519080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 519180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If result is not supposed to be flat allocate a cons string object. If both 519280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // strings are ascii the result is an ascii cons string. 519380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_ascii, allocated, ascii_data; 519480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); 519580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); 519680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 519780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); 519880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(ecx, Operand(edi)); 5199589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 5200589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 5201589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ test(ecx, Immediate(kStringEncodingMask)); 520280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &non_ascii); 520380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&ascii_data); 520480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate an acsii cons string. 520580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); 520680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&allocated); 520780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fill the fields of the cons string. 520880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) __ AbortIfNotSmi(ebx); 520980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); 521080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), 521180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(String::kEmptyHashField)); 521280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); 521380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); 521480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, ecx); 521544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 521680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 521780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_ascii); 521880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // At least one of the strings is two-byte. Check whether it happens 521980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // to contain only ascii characters. 522080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: first instance type AND second instance type. 522180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: second instance type. 522280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Immediate(kAsciiDataHintMask)); 522380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &ascii_data); 522480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 522580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 522680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(edi, Operand(ecx)); 522780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); 522880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(edi, kAsciiStringTag | kAsciiDataHintTag); 522980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); 523080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &ascii_data); 523180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate a two byte cons string. 5232589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ AllocateTwoByteConsString(ecx, edi, no_reg, &string_add_runtime); 523380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&allocated); 523480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 523580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle creating a flat result. First check that both strings are not 523680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // external strings. 523780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first string 523880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: length of resulting flat string as a smi 523980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: second string 524080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&string_add_flat_result); 524180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 524280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 524380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(ecx, kStringRepresentationMask); 524480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(ecx, kExternalStringTag); 524580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &string_add_runtime); 524680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 524780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 524880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(ecx, kStringRepresentationMask); 524980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(ecx, kExternalStringTag); 525080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &string_add_runtime); 525169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // We cannot encounter sliced strings here since: 525269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); 525380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Now check if both strings are ascii strings. 525480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first string 525580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: length of resulting flat string as a smi 525680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: second string 525780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_ascii_string_add_flat_result; 5258589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 5259589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 526080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 5261589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); 526280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &non_ascii_string_add_flat_result); 526380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 5264589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); 526580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &string_add_runtime); 526680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 526780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both strings are ascii strings. As they are short they are both flat. 526880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: length of resulting flat string as a smi 526980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ebx); 527080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime); 527180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 527280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, eax); 527380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 527480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 527580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load first argument and locate first character. 527680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 2 * kPointerSize)); 527780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 527880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edi); 527980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 528080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 528180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: first character of result 528280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: first char of first argument 528380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: length of first argument 528480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); 528580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load second argument and locate first character. 528680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 1 * kPointerSize)); 528780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 528880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edi); 528980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 529080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 529180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: next character of result 529280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: first char of second argument 529380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: length of second argument 529480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); 529544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 529680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 529780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 529880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle creating a flat two byte result. 529980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first string - known to be two byte 530080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: length of resulting flat string as a smi 530180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: second string 530280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_ascii_string_add_flat_result); 530380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 5304589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); 530580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &string_add_runtime); 530680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both strings are two byte strings. As they are short they are both 530780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // flat. 530880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ebx); 530980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); 531080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 531180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, eax); 531280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 531380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(ecx), 531480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 531580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load first argument and locate first character. 531680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 2 * kPointerSize)); 531780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 531880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edi); 531980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), 532080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 532180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 532280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: first character of result 532380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: first char of first argument 532480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: length of first argument 532580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); 532680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load second argument and locate first character. 532780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 1 * kPointerSize)); 532880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 532980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edi); 533080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 533180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 533280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: next character of result 533380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: first char of second argument 533480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: length of second argument 533580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); 533644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 533780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 533880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 533980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump to runtime to add the two strings. 534080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&string_add_runtime); 534180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kStringAdd, 2, 1); 53429ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 53439ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick if (call_builtin.is_linked()) { 53449ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(&call_builtin); 53459ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); 53469ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick } 53479ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick} 53489ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 53499ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 53509ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrickvoid StringAddStub::GenerateConvertArgument(MacroAssembler* masm, 53519ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick int stack_offset, 53529ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Register arg, 53539ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Register scratch1, 53549ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Register scratch2, 53559ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Register scratch3, 53569ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label* slow) { 53579ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // First check if the argument is already a string. 53589ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label not_string, done; 53593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(arg, ¬_string); 53609ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); 53619ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ j(below, &done); 53629ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 53639ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Check the number to string cache. 53649ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label not_cached; 53659ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(¬_string); 53669ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Puts the cached result into scratch1. 53679ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick NumberToStringStub::GenerateLookupNumberStringCache(masm, 53689ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick arg, 53699ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick scratch1, 53709ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick scratch2, 53719ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick scratch3, 53729ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick false, 53739ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick ¬_cached); 53749ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(arg, scratch1); 53759ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(Operand(esp, stack_offset), arg); 53769ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ jmp(&done); 53779ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 53789ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Check if the argument is a safe string wrapper. 53799ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(¬_cached); 53803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(arg, slow); 53819ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1); // map -> scratch1. 53829ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ j(not_equal, slow); 53839ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ test_b(FieldOperand(scratch1, Map::kBitField2Offset), 53849ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 1 << Map::kStringWrapperSafeForDefaultValueOf); 53859ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ j(zero, slow); 53869ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(arg, FieldOperand(arg, JSValue::kValueOffset)); 53879ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(Operand(esp, stack_offset), arg); 53889ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 53899ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(&done); 539080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 539180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 539280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 539380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharacters(MacroAssembler* masm, 539480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register dest, 539580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register src, 539680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register count, 539780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch, 539880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool ascii) { 5399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop; 540080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 540180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // This loop just copies one character at a time, as it is only used for very 540280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // short strings. 540380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (ascii) { 540480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_b(scratch, Operand(src, 0)); 540580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_b(Operand(dest, 0), scratch); 540680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(src), Immediate(1)); 540780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(dest), Immediate(1)); 540880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 540980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_w(scratch, Operand(src, 0)); 541080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_w(Operand(dest, 0), scratch); 541180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(src), Immediate(2)); 541280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(dest), Immediate(2)); 541380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 541480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(count), Immediate(1)); 541580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &loop); 541680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 541780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 541880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 541980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, 542080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register dest, 542180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register src, 542280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register count, 542380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch, 542480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool ascii) { 542580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy characters using rep movs of doublewords. 542680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The destination is aligned on a 4 byte boundary because we are 542780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // copying to the beginning of a newly allocated string. 542880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(dest.is(edi)); // rep movs destination 542980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(src.is(esi)); // rep movs source 543080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(count.is(ecx)); // rep movs count 543180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(dest)); 543280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(src)); 543380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(count)); 543480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 543580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Nothing to do for zero characters. 543680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label done; 543780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(count, Operand(count)); 543880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &done); 543980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 544080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make count the number of bytes to copy. 544180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!ascii) { 544280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(count, 1); 544380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 544480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 544580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Don't enter the rep movs if there are less than 4 bytes to copy. 5446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label last_bytes; 544780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(count, Immediate(~3)); 5448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &last_bytes, Label::kNear); 544980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 545080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy from edi to esi using rep movs instruction. 545180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, count); 545280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sar(count, 2); // Number of doublewords to copy. 545380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cld(); 545480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ rep_movs(); 545580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 545680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find number of bytes left. 545780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(count, scratch); 545880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(count, 3); 545980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 546080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if there are more bytes to copy. 546180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&last_bytes); 546280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(count, Operand(count)); 546380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &done); 546480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 546580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy remaining characters. 5466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop; 546780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 546880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_b(scratch, Operand(src, 0)); 546980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_b(Operand(dest, 0), scratch); 547080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(src), Immediate(1)); 547180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(dest), Immediate(1)); 547280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(count), Immediate(1)); 547380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &loop); 547480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 547580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 547680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 547780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 547880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 547980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, 548080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register c1, 548180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register c2, 548280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 548380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 548480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch3, 54859ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label* not_probed, 548680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_found) { 548780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Register scratch3 is the general scratch register in this function. 548880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch = scratch3; 548980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 549080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure that both characters are not digits as such strings has a 549180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // different hash algorithm. Don't try to look for these in the symbol table. 5492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_array_index; 549380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, c1); 549480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(scratch), Immediate(static_cast<int>('0'))); 549580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0'))); 5496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above, ¬_array_index, Label::kNear); 549780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, c2); 549880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(scratch), Immediate(static_cast<int>('0'))); 549980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0'))); 55009ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ j(below_equal, not_probed); 550180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 550280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_array_index); 550380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate the two character string hash. 550480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash = scratch1; 550580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateHashInit(masm, hash, c1, scratch); 550680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateHashAddCharacter(masm, hash, c2, scratch); 550780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateHashGetHash(masm, hash, scratch); 550880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 550980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Collect the two characters in a register. 551080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register chars = c1; 551180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(c2, kBitsPerByte); 551280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ or_(chars, Operand(c2)); 551380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 551480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 551580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash: hash of two character string. 551680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 551780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the symbol table. 551880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register symbol_table = c2; 551944f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference roots_address = 552044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::roots_address(masm->isolate()); 552180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex)); 552280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(symbol_table, 552380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Operand::StaticArray(scratch, times_pointer_size, roots_address)); 552480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 552580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate capacity mask from the symbol table capacity. 552680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register mask = scratch2; 552780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); 552880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(mask); 552980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(Operand(mask), Immediate(1)); 553080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 553180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Registers 553280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 553380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash: hash of two character string 553480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // symbol_table: symbol table 553580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // mask: capacity mask 553680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // scratch: - 553780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 553880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Perform a number of probes in the symbol table. 553980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kProbes = 4; 554080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label found_in_symbol_table; 554180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label next_probe[kProbes], next_probe_pop_mask[kProbes]; 5542692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch Register candidate = scratch; // Scratch register contains candidate. 554380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = 0; i < kProbes; i++) { 554480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate entry in symbol table. 554580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 554680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (i > 0) { 554780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(scratch), Immediate(SymbolTable::GetProbeOffset(i))); 554880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 554980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(scratch, Operand(mask)); 555080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 555180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the entry from the symbol table. 555280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(SymbolTable::kEntrySize == 1); 555380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(candidate, 555480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(symbol_table, 555580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch, 555680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_pointer_size, 555780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SymbolTable::kElementsStartOffset)); 555880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 555980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If entry is undefined no string with this hash can be found. 556044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 556144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(candidate, factory->undefined_value()); 556280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, not_found); 556344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(candidate, factory->null_value()); 556444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ j(equal, &next_probe[i]); 556580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 556680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If length is not 2 the string is not a candidate. 556780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(candidate, String::kLengthOffset), 556880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(Smi::FromInt(2))); 556980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &next_probe[i]); 557080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 557180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // As we are out of registers save the mask on the stack and use that 557280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // register as a temporary. 557380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(mask); 557480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register temp = mask; 557580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 557680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the candidate is a non-external ascii string. 557780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); 557880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); 557980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfInstanceTypeIsNotSequentialAscii( 558080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen temp, temp, &next_probe_pop_mask[i]); 558180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 558280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the two characters match. 558380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); 558480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(temp, 0x0000ffff); 558580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(chars, Operand(temp)); 558680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &found_in_symbol_table); 558780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&next_probe_pop_mask[i]); 558880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(mask); 558980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&next_probe[i]); 559080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 559180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 559280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // No matching 2 character string found by probing. 559380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(not_found); 559480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 559580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Scratch register contains result when we fall through to here. 5596692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch Register result = candidate; 559780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&found_in_symbol_table); 559880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(mask); // Pop saved mask from the stack. 559980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!result.is(eax)) { 560080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, result); 560180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 560280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 560380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 560480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 560580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashInit(MacroAssembler* masm, 560680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 560780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register character, 560880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 5609692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch // hash = (seed + character) + ((seed + character) << 10); 5610692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch if (Serializer::enabled()) { 5611692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch ExternalReference roots_address = 5612692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch ExternalReference::roots_address(masm->isolate()); 5613692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ mov(scratch, Immediate(Heap::kStringHashSeedRootIndex)); 5614692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ mov(scratch, Operand::StaticArray(scratch, 5615692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch times_pointer_size, 5616692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch roots_address)); 5617692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ add(scratch, Operand(character)); 5618692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ mov(hash, scratch); 5619692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ shl(scratch, 10); 5620692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ add(hash, Operand(scratch)); 5621692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch } else { 5622692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch int32_t seed = masm->isolate()->heap()->StringHashSeed(); 5623692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ lea(scratch, Operand(character, seed)); 5624692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ shl(scratch, 10); 5625692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ lea(hash, Operand(scratch, character, times_1, seed)); 5626692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch } 562780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 6; 562880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 5629692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ shr(scratch, 6); 563080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(hash, Operand(scratch)); 563180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 563280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 563380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 563480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, 563580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 563680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register character, 563780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 563880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += character; 563980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(hash, Operand(character)); 564080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 10; 564180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 564280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(scratch, 10); 564380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(hash, Operand(scratch)); 564480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 6; 564580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 5646692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ shr(scratch, 6); 564780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(hash, Operand(scratch)); 564880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 564980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 565080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 565180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashGetHash(MacroAssembler* masm, 565280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 565380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 565480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 3; 565580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 565680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(scratch, 3); 565780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(hash, Operand(scratch)); 565880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 11; 565980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 5660692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ shr(scratch, 11); 566180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(hash, Operand(scratch)); 566280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 15; 566380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 566480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(scratch, 15); 566580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(hash, Operand(scratch)); 566680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5667692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ and_(hash, String::kHashBitMask); 5668692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch 566980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // if (hash == 0) hash = 27; 5670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label hash_not_zero; 5671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &hash_not_zero, Label::kNear); 5672692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ mov(hash, Immediate(StringHasher::kZeroHash)); 567380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&hash_not_zero); 567480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 567580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 567680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 567780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid SubStringStub::Generate(MacroAssembler* masm) { 567880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 567980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 568080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 568180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[0]: return address 568280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[4]: to 568380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[8]: from 568480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[12]: string 568580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 568680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure first argument is a string. 568780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, 3 * kPointerSize)); 568880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 56893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &runtime); 569080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); 569180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(NegateCondition(is_string), &runtime); 569280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 569380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: string 569480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: instance type 569580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 569680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate length of sub string using the smi values. 569780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label result_longer_than_two; 569880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index. 56993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(ecx, &runtime); 570080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index. 57013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(edx, &runtime); 570280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(ecx, Operand(edx)); 570380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(ecx, FieldOperand(eax, String::kLengthOffset)); 570480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label return_eax; 570580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &return_eax); 570680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Special handling of sub-strings of length 1 and 2. One character strings 570780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // are handled in the runtime system (looked up in the single character 570880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // cache). Two character strings are looked for in the symbol cache. 570980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ecx); // Result length is no longer smi. 571080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(ecx, 2); 571180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(greater, &result_longer_than_two); 571280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(less, &runtime); 571380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 571480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Sub string of length 2 requested. 571580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: string 571680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: instance type 571780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: sub string length (value is 2) 571880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: from index (smi) 571980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &runtime); 572080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 572180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the two characters forming the sub string. 572280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edx); // From index is no longer smi. 572380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ebx, FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize)); 572480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, 572580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize + 1)); 572680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 572780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try to lookup two character string in symbol table. 572880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label make_two_character_string; 572980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateTwoCharacterSymbolTableProbe( 57309ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick masm, ebx, ecx, eax, edx, edi, 57319ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick &make_two_character_string, &make_two_character_string); 573280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 573380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 573480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&make_two_character_string); 573580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Setup registers for allocating the two character string. 573680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, 3 * kPointerSize)); 573780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 573880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 573980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(ecx, Immediate(2)); 574080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 574169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (FLAG_string_slices) { 574269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label copy_routine; 574369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If coming from the make_two_character_string path, the string 574469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // is too short to be sliced anyways. 574569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(2 < SlicedString::kMinLength); 574669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(©_routine); 574769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&result_longer_than_two); 574869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 574969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // eax: string 575069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // ebx: instance type 575169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // ecx: sub string length 575269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // edx: from index (smi) 575369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label allocate_slice, sliced_string, seq_string; 575469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(ecx, SlicedString::kMinLength); 575569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Short slice. Copy instead of slicing. 575669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(less, ©_routine); 575769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kSeqStringTag == 0); 575869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ test(ebx, Immediate(kStringRepresentationMask)); 575969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &seq_string, Label::kNear); 576069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); 576169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kIsIndirectStringMask != 0); 576269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ test(ebx, Immediate(kIsIndirectStringMask)); 576369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // External string. Jump to runtime. 576469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &runtime); 576569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 576669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Factory* factory = masm->isolate()->factory(); 576769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ test(ebx, Immediate(kSlicedNotConsMask)); 576869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_zero, &sliced_string, Label::kNear); 576969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Cons string. Check whether it is flat, then fetch first part. 577069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(FieldOperand(eax, ConsString::kSecondOffset), 577169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch factory->empty_string()); 577269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_equal, &runtime); 577369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(edi, FieldOperand(eax, ConsString::kFirstOffset)); 577469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&allocate_slice, Label::kNear); 577569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 577669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&sliced_string); 577769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Sliced string. Fetch parent and correct start index by offset. 577869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset)); 577969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(edi, FieldOperand(eax, SlicedString::kParentOffset)); 578069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&allocate_slice, Label::kNear); 578169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 578269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&seq_string); 578369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Sequential string. Just move string to the right register. 578469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(edi, eax); 578569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 578669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&allocate_slice); 578769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // edi: underlying subject string 578869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // ebx: instance type of original subject string 578969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // edx: offset 579069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // ecx: length 579169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Allocate new sliced string. At this point we do not reload the instance 579269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // type including the string encoding because we simply rely on the info 579369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // provided by the original string. It does not matter if the original 579469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // string's encoding is wrong because we always have to recheck encoding of 579569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // the newly created string's parent anyways due to externalized strings. 579669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label two_byte_slice, set_slice_header; 5797589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 5798589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 5799589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ test(ebx, Immediate(kStringEncodingMask)); 580069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &two_byte_slice, Label::kNear); 580169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ AllocateAsciiSlicedString(eax, ebx, no_reg, &runtime); 580269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&set_slice_header, Label::kNear); 580369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&two_byte_slice); 5804589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime); 580569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&set_slice_header); 580669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx); 580769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ SmiTag(ecx); 580869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx); 580969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(FieldOperand(eax, SlicedString::kParentOffset), edi); 581069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(FieldOperand(eax, SlicedString::kHashFieldOffset), 581169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Immediate(String::kEmptyHashField)); 581269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&return_eax); 581369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 581469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(©_routine); 581569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } else { 581669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&result_longer_than_two); 581769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 581869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 581980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: string 582080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: instance type 582180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result string length 582280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for flat ascii string 582380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_ascii_flat; 582480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &non_ascii_flat); 582580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 582680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate the result. 582780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime); 582880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 582980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 583080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result string length 583180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, esi); // esi used by following code. 583280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 583380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, eax); 583480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 583580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load string argument and locate character of sub string start. 583680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(esi, Operand(esp, 3 * kPointerSize)); 583780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(esi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 583880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(esp, 2 * kPointerSize)); // from 583980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ebx); 584080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(esi, Operand(ebx)); 584180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 584280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 584380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result length 584480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: original value of esi 584580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: first character of result 584680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: character of sub string start 584780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); 584880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(esi, edx); // Restore esi. 584944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 585044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->sub_string_native(), 1); 585180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 585280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 585380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_ascii_flat); 585480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: string 585580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: instance type & kStringRepresentationMask | kStringEncodingMask 585680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result string length 585780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for flat two byte string 585880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(ebx, kSeqStringTag | kTwoByteStringTag); 585980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 586080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 586180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate the result. 586280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime); 586380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 586480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 586580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result string length 586680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, esi); // esi used by following code. 586780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 586880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, eax); 586980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(edi), 587080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 587180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load string argument and locate character of sub string start. 587280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(esi, Operand(esp, 3 * kPointerSize)); 587380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(esi), 587480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 587580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(esp, 2 * kPointerSize)); // from 587680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // As from is a smi it is 2 times the value which matches the size of a two 587780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // byte character. 587880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 587980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 588080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(esi, Operand(ebx)); 588180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 588280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 588380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result length 588480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: original value of esi 588580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: first character of result 588680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: character of sub string start 588780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); 588880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(esi, edx); // Restore esi. 588980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 589080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&return_eax); 589144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->sub_string_native(), 1); 589280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 589380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 589480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump to runtime to create the sub string. 589580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 589680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kSubString, 3, 1); 589780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 589880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 589980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, 5901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left, 5902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right, 5903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch1, 5904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch2) { 5905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register length = scratch1; 5906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare lengths. 5908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label strings_not_equal, check_zero_length; 5909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(length, FieldOperand(left, String::kLengthOffset)); 5910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(length, FieldOperand(right, String::kLengthOffset)); 5911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &check_zero_length, Label::kNear); 5912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&strings_not_equal); 5913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL))); 5914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 5915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the length is zero. 5917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label compare_chars; 5918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&check_zero_length); 5919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 5920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(length, Operand(length)); 5921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &compare_chars, Label::kNear); 5922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 5923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 5924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare characters. 5926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&compare_chars); 5927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2, 5928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch &strings_not_equal, Label::kNear); 5929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Characters are equal. 5931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 5932257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 5933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 5934257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 593680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, 593780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register left, 593880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register right, 593980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 594080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 594180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch3) { 594244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 594344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_compare_native(), 1); 594480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 594580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find minimum length. 5946257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label left_shorter; 594780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); 594880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch3, scratch1); 594980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); 595080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 595180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register length_delta = scratch3; 595280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(less_equal, &left_shorter, Label::kNear); 595480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Right string is shorter. Change scratch1 to be length of right string. 595580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(scratch1, Operand(length_delta)); 595680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&left_shorter); 595780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 595880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register min_length = scratch1; 595980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 596080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If either length is zero, just compare lengths. 5961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label compare_lengths; 596280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(min_length, Operand(min_length)); 5963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &compare_lengths, Label::kNear); 596480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare characters. 5966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label result_not_equal; 5967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2, 5968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch &result_not_equal, Label::kNear); 596980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 597080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compare lengths - strings up to min-length are equal. 597180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&compare_lengths); 597280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(length_delta, Operand(length_delta)); 5973257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &result_not_equal, Label::kNear); 597480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 597580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is EQUAL. 597680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(EQUAL == 0); 597780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 597880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 597980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 598080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label result_greater; 598280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&result_not_equal); 5983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(greater, &result_greater, Label::kNear); 598480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 598580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is LESS. 598680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(LESS))); 598780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 598880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 598980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is GREATER. 599080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&result_greater); 599180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(GREATER))); 599280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 599380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 599480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 599580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateAsciiCharsCompareLoop( 5997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 5998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left, 5999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right, 6000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register length, 6001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch, 6002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* chars_not_equal, 6003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance chars_not_equal_near) { 6004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Change index to run from -length to -1 by adding length to string 6005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // start. This means that loop ends when index reaches zero, which 6006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // doesn't need an additional compare. 6007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiUntag(length); 6008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(left, 6009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize)); 6010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(right, 6011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize)); 6012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ neg(length); 6013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register index = length; // index = -length; 6014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare loop. 6016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop; 6017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&loop); 6018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov_b(scratch, Operand(left, index, times_1, 0)); 6019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmpb(scratch, Operand(right, index, times_1, 0)); 6020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, chars_not_equal, chars_not_equal_near); 6021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(Operand(index), Immediate(1)); 6022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &loop); 6023257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6024257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6025257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 602680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::Generate(MacroAssembler* masm) { 602780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 602880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 602980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 603080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[0]: return address 603180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[4]: right string 603280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[8]: left string 603380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 603480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 2 * kPointerSize)); // left 603580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, 1 * kPointerSize)); // right 603680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6037257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_same; 603880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, Operand(eax)); 6039257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, ¬_same, Label::kNear); 604080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(EQUAL == 0); 604180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 604280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 604344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(masm->isolate()->counters()->string_compare_native(), 1); 604480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 604580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 604680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_same); 604780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 604880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that both objects are sequential ascii strings. 604980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); 605080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 605180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compare flat ascii strings. 605280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Drop arguments from the stack. 605380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ecx); 605480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(Operand(esp), Immediate(2 * kPointerSize)); 605580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ecx); 605680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); 605780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 605880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 605980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // tagged as a small integer. 606080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 606180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 606280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 606380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateSmis(MacroAssembler* masm) { 6066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(state_ == CompareIC::SMIS); 6067257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 6068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(edx)); 6069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ or_(ecx, Operand(eax)); 60703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(ecx, &miss, Label::kNear); 6071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (GetCondition() == equal) { 6073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // For equality we do not care about the sign of the result. 6074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(eax, Operand(edx)); 6075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 6076257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done; 6077b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(edx, Operand(eax)); 6078257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(no_overflow, &done, Label::kNear); 6079b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Correct sign of result in case of overflow. 6080b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ not_(edx); 6081b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&done); 6082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, edx); 6083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 6084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 6085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6086b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&miss); 6087b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateMiss(masm); 6088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 6089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6090b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6091b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { 6092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(state_ == CompareIC::HEAP_NUMBERS); 6093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label generic_stub; 6095257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label unordered; 6096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 6097b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(edx)); 6098b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ and_(ecx, Operand(eax)); 60993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(ecx, &generic_stub, Label::kNear); 6100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6101b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx); 6102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 6103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); 6104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 6105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Inlining the double comparison and falling back to the general compare 6107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // stub if NaN is involved or SS2 or CMOV is unsupported. 61088b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { 6109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope scope1(SSE2); 6110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope scope2(CMOV); 6111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Load left and right operand 6113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 6114b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 6115b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6116b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Compare operands 6117b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm0, xmm1); 6118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Don't base result on EFLAGS when a NaN is involved. 6120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(parity_even, &unordered, Label::kNear); 6121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Return a result of -1, 0, or 1, based on EFLAGS. 6123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Performing mov, because xor would destroy the flag register. 6124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, 0); // equal 6125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Immediate(Smi::FromInt(1))); 6126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmov(above, eax, Operand(ecx)); 6127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Immediate(Smi::FromInt(-1))); 6128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmov(below, eax, Operand(ecx)); 6129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 6130b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&unordered); 6132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 6133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); 6135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&generic_stub); 6136b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); 6137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&miss); 6139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateMiss(masm); 6140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 6141b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6142b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateSymbols(MacroAssembler* masm) { 6144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(state_ == CompareIC::SYMBOLS); 6145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(GetCondition() == equal); 6146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 6148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = edx; 6149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = eax; 6150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp1 = ecx; 6151257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp2 = ebx; 6152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are heap objects. 6154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 6155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp1, Operand(left)); 6156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 6157257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(tmp1, Operand(right)); 61583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(tmp1, &miss, Label::kNear); 6159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6160257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are symbols. 6161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); 6162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); 6163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); 6164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); 6165257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSymbolTag != 0); 6166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(tmp1, Operand(tmp2)); 6167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(tmp1, Immediate(kIsSymbolMask)); 6168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &miss, Label::kNear); 6169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Symbols are compared by identity. 6171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done; 6172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(left, Operand(right)); 6173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Make sure eax is non-zero. At this point input operands are 6174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // guaranteed to be non-zero. 6175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(right.is(eax)); 6176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &done, Label::kNear); 6177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(EQUAL == 0); 6178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 6179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&done); 6181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 6182257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6183257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&miss); 6184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateMiss(masm); 6185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6186257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateStrings(MacroAssembler* masm) { 6189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(state_ == CompareIC::STRINGS); 6190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(GetCondition() == equal); 6191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 6192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 6194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = edx; 6195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = eax; 6196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp1 = ecx; 6197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp2 = ebx; 6198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp3 = edi; 6199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are heap objects. 6201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp1, Operand(left)); 6202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 6203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(tmp1, Operand(right)); 62043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(tmp1, &miss); 6205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are strings. This leaves the instance 6207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // types loaded in tmp1 and tmp2. 6208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); 6209257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); 6210257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); 6211257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); 6212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp3, tmp1); 6213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kNotStringTag != 0); 6214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ or_(tmp3, Operand(tmp2)); 6215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(tmp3, Immediate(kIsNotStringMask)); 6216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &miss); 6217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Fast check for identical strings. 6219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_same; 6220257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(left, Operand(right)); 6221257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, ¬_same, Label::kNear); 6222257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(EQUAL == 0); 6223257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 6224257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6225257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 6226257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6227257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle not identical strings. 6228257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(¬_same); 6229257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6230257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both strings are symbols. If they are, we're done 6231257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // because we already know they are not identical. 6232257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label do_compare; 6233257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSymbolTag != 0); 6234257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(tmp1, Operand(tmp2)); 6235257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(tmp1, Immediate(kIsSymbolMask)); 6236257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &do_compare, Label::kNear); 6237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Make sure eax is non-zero. At this point input operands are 6238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // guaranteed to be non-zero. 6239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(right.is(eax)); 6240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 6241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6242257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both strings are sequential ASCII. 6243257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label runtime; 6244257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&do_compare); 6245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime); 6246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare flat ASCII strings. Returns when done. 6248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringCompareStub::GenerateFlatAsciiStringEquals( 6249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch masm, left, right, tmp1, tmp2); 6250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle more complex cases in runtime. 6252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&runtime); 6253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(tmp1); // Return address. 6254257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(left); 6255257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(right); 6256257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(tmp1); 6257257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ TailCallRuntime(Runtime::kStringEquals, 2, 1); 6258257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6259257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&miss); 6260257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateMiss(masm); 6261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6263257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateObjects(MacroAssembler* masm) { 6265b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(state_ == CompareIC::OBJECTS); 6266257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 6267b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(edx)); 6268b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ and_(ecx, Operand(eax)); 62693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(ecx, &miss, Label::kNear); 6270b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6271b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); 6272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 6273b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); 6274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 6275b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6276b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(GetCondition() == equal); 6277b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(eax, Operand(edx)); 6278b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 6279b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6280b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&miss); 6281b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateMiss(masm); 6282b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 6283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateMiss(MacroAssembler* masm) { 6286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Save the registers. 6287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(ecx); 6288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(edx); 6289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(eax); 6290b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(ecx); 6291b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6292b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Call the runtime system in a fresh internal frame. 629344f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss), 629444f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 6295b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ EnterInternalFrame(); 6296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(edx); 6297b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(eax); 6298b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(op_))); 6299b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CallExternalReference(miss, 3); 6300b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ LeaveInternalFrame(); 6301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6302b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Compute the entry point of the rewritten stub. 6303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ lea(edi, FieldOperand(eax, Code::kHeaderSize)); 6304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Restore registers. 6306b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(ecx); 6307b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(eax); 6308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(edx); 6309b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(ecx); 6310b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6311b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Do a tail call to the rewritten stub. 6312b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(Operand(edi)); 6313b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 6314b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6315b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Helper function used to check that the dictionary doesn't contain 6317257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// the property. This function may return false negatives, so miss_label 6318257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// must always call a backup property check that is complete. 6319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// This function is safe to call if the receiver has fast properties. 6320257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Name must be a symbol and receiver must be a heap object. 6321257744e915dfc84d6d07a6b2accf8402d9ffc708Ben MurdochMaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup( 6322257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 6323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* miss, 6324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* done, 6325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register properties, 6326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch String* name, 6327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register r0) { 6328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(name->IsSymbol()); 6329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6330257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If names of slots in range from 1 to kProbes - 1 for the hash value are 6331257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // not equal to the name and kProbes-th slot is not used (its name is the 6332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // undefined value), it guarantees the hash table doesn't contain the 6333257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // property. It's true even if some slots represent deleted properties 6334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // (their names are the null value). 6335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = 0; i < kInlinedProbes; i++) { 6336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 6337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register index = r0; 6338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Capacity is smi 2^n. 6339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(index, FieldOperand(properties, kCapacityOffset)); 6340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ dec(index); 6341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(Operand(index), 6342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Immediate(Smi::FromInt(name->Hash() + 6343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionary::GetProbeOffset(i)))); 6344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the entry size. 6346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 6347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. 6348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register entity_name = r0; 6349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Having undefined at this place means the name is not contained. 6350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT_EQ(kSmiTagSize, 1); 6351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(entity_name, Operand(properties, index, times_half_pointer_size, 6352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kElementsStartOffset - kHeapObjectTag)); 6353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(entity_name, masm->isolate()->factory()->undefined_value()); 6354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, done); 6355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Stop if found the property. 6357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(entity_name, Handle<String>(name)); 6358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, miss); 6359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the entry name is not a symbol. 6361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); 6362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset), 6363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kIsSymbolMask); 6364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, miss); 6365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionaryLookupStub stub(properties, 6368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 6369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 6370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionaryLookupStub::NEGATIVE_LOOKUP); 6371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(Immediate(Handle<Object>(name))); 6372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(Immediate(name->Hash())); 6373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MaybeObject* result = masm->TryCallStub(&stub); 6374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (result->IsFailure()) return result; 6375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(r0, Operand(r0)); 6376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, miss); 6377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(done); 6378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch return result; 6379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Probe the string dictionary in the |elements| register. Jump to the 6383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// |done| label if a property with the given name is found leaving the 6384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// index into the dictionary in |r0|. Jump to the |miss| label 6385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// otherwise. 6386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, 6387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* miss, 6388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* done, 6389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register elements, 6390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register name, 6391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register r0, 6392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register r1) { 6393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Assert that name contains a string. 6394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (FLAG_debug_code) __ AbortIfNotString(name); 6395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r1, FieldOperand(elements, kCapacityOffset)); 6397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(r1, kSmiTagSize); // convert smi to int 6398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ dec(r1); 6399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Generate an unrolled loop that performs a few probes before 6401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // giving up. Measurements done on Gmail indicate that 2 probes 6402257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // cover ~93% of loads from dictionaries. 6403257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = 0; i < kInlinedProbes; i++) { 6404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 6405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); 6406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(r0, String::kHashShift); 6407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i > 0) { 6408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i))); 6409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(r0, Operand(r1)); 6411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the entry size. 6413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 6414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3 6415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the key is identical to the name. 6417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(name, Operand(elements, 6418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 6419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch times_4, 6420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kElementsStartOffset - kHeapObjectTag)); 6421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, done); 6422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionaryLookupStub stub(elements, 6425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r1, 6426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 6427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch POSITIVE_LOOKUP); 6428257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(name); 6429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); 6430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(r0, String::kHashShift); 6431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(r0); 6432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallStub(&stub); 6433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(r1, Operand(r1)); 6435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, miss); 6436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(done); 6437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::Generate(MacroAssembler* masm) { 6441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Stack frame on entry: 6442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // esp[0 * kPointerSize]: return address. 6443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // esp[1 * kPointerSize]: key's hash. 6444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // esp[2 * kPointerSize]: key. 6445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers: 6446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // dictionary_: StringDictionary to probe. 6447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // result_: used as scratch. 6448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // index_: will hold an index of entry if lookup is successful. 6449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // might alias with result_. 6450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Returns: 6451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // result_ is zero if lookup failed, non zero otherwise. 6452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label in_dictionary, maybe_in_dictionary, not_in_dictionary; 6454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch = result_; 6456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset)); 6458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ dec(scratch); 6459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiUntag(scratch); 6460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(scratch); 6461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If names of slots in range from 1 to kProbes - 1 for the hash value are 6463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // not equal to the name and kProbes-th slot is not used (its name is the 6464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // undefined value), it guarantees the hash table doesn't contain the 6465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // property. It's true even if some slots represent deleted properties 6466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // (their names are the null value). 6467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = kInlinedProbes; i < kTotalProbes; i++) { 6468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 6469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, Operand(esp, 2 * kPointerSize)); 6470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i > 0) { 6471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(Operand(scratch), 6472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Immediate(StringDictionary::GetProbeOffset(i))); 6473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(scratch, Operand(esp, 0)); 6475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the entry size. 6477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 6478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. 6479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Having undefined at this place means the name is not contained. 6481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT_EQ(kSmiTagSize, 1); 6482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, Operand(dictionary_, 6483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch index_, 6484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch times_pointer_size, 6485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kElementsStartOffset - kHeapObjectTag)); 6486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(scratch, masm->isolate()->factory()->undefined_value()); 6487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, ¬_in_dictionary); 6488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Stop if found the property. 6490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(scratch, Operand(esp, 3 * kPointerSize)); 6491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &in_dictionary); 6492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { 6494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If we hit a non symbol key during negative lookup 6495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // we have to bailout as this key might be equal to the 6496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // key we are looking for. 6497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the entry name is not a symbol. 6499257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); 6500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset), 6501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kIsSymbolMask); 6502257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &maybe_in_dictionary); 6503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6505257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&maybe_in_dictionary); 6507257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If we are doing negative lookup then probing failure should be 6508257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // treated as a lookup success. For positive lookup probing failure 6509257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // should be treated as lookup failure. 6510257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (mode_ == POSITIVE_LOOKUP) { 6511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(result_, Immediate(0)); 6512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Drop(1); 6513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 6514257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&in_dictionary); 6517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(result_, Immediate(1)); 6518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Drop(1); 6519257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 6520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6521257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(¬_in_dictionary); 6522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(result_, Immediate(0)); 6523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Drop(1); 6524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 6525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6526257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 652880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#undef __ 652980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 653080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} } // namespace v8::internal 653180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 653280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif // V8_TARGET_ARCH_IA32 6533