13ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Copyright 2012 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" 373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#include "stub-cache.h" 383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#include "codegen.h" 3980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsennamespace v8 { 4180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsennamespace internal { 4280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#define __ ACCESS_MASM(masm) 441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid ToNumberStub::Generate(MacroAssembler* masm) { 461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // The ToNumber stub takes one argument in eax. 47257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label check_heap_number, call_builtin; 483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &check_heap_number, Label::kNear); 491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&check_heap_number); 521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 5344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ebx, Immediate(factory->heap_number_map())); 55257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &call_builtin, Label::kNear); 561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&call_builtin); 591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ pop(ecx); // Pop return address. 601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(eax); 611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(ecx); // Push return address. 621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); 631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 6680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewClosureStub::Generate(MacroAssembler* masm) { 6780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Create a new closure from the given function info in new 6880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // space. Set the context to the current context in esi. 6980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label gc; 7080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateInNewSpace(JSFunction::kSize, eax, ebx, ecx, &gc, TAG_OBJECT); 7180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 7280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the function info from the stack. 7380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 1 * kPointerSize)); 7480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int map_index = (language_mode_ == CLASSIC_MODE) 763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ? Context::FUNCTION_MAP_INDEX 773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch : Context::STRICT_MODE_FUNCTION_MAP_INDEX; 7844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 7980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compute the function map in the current global context and set that 8080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // as the map of the allocated object. 8180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 8280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset)); 8344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(ecx, Operand(ecx, Context::SlotOffset(map_index))); 8480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSObject::kMapOffset), ecx); 8580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 8680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Initialize the rest of the function. We don't have to update the 8780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // write barrier because the allocated object is in new space. 8844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 8944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(ebx, Immediate(factory->empty_fixed_array())); 9080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ebx); 9180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx); 9280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset), 9344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(factory->the_hole_value())); 9480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset), edx); 9580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSFunction::kContextOffset), esi); 9680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSFunction::kLiteralsOffset), ebx); 97b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSFunction::kNextFunctionLinkOffset), 9844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(factory->undefined_value())); 9980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 10080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Initialize the code pointer in the function to be the one 10180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // found in the shared function info object. 10280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); 10380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); 10480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSFunction::kCodeEntryOffset), edx); 10580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 10680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameter. 10780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(1 * kPointerSize); 10880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 10980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Create a new closure through the slower runtime call. 11080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&gc); 11180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ecx); // Temporarily remove return address. 11280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(edx); 11380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(esi); 11480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(edx); 11544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(Immediate(factory->false_value())); 11680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ecx); // Restore return address. 1178a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ TailCallRuntime(Runtime::kNewClosure, 3, 1); 11880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 11980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 12080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 12180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewContextStub::Generate(MacroAssembler* masm) { 12280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try to allocate the context in new space. 12380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label gc; 12480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int length = slots_ + Context::MIN_CONTEXT_SLOTS; 12580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, 12680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen eax, ebx, ecx, &gc, TAG_OBJECT); 12780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 12880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the function from the stack. 12980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esp, 1 * kPointerSize)); 13080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up the object header. 13244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 1333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(eax, HeapObject::kMapOffset), 1343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch factory->function_context_map()); 13580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, Context::kLengthOffset), 13680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(Smi::FromInt(length))); 13780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up the fixed slots. 1399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Set(ebx, Immediate(0)); // Set to NULL. 14080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx); 1413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), esi); 14280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(eax, Context::SlotOffset(Context::EXTENSION_INDEX)), ebx); 14380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy the global object from the previous context. 1453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 14680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx); 14780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 14880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Initialize the rest of the slots to undefined. 14944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(ebx, factory->undefined_value()); 15080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { 15180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(eax, Context::SlotOffset(i)), ebx); 15280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 15380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 15480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameter. 1553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(esi, eax); 15680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(1 * kPointerSize); 15780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 15880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Need to collect. Call into runtime system. 15980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&gc); 1603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1); 16180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 16280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 16380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid FastNewBlockContextStub::Generate(MacroAssembler* masm) { 1653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Stack layout on entry: 1663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // 1673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // [esp + (1 * kPointerSize)]: function 1683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // [esp + (2 * kPointerSize)]: serialized scope info 1693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Try to allocate the context in new space. 1713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label gc; 1723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int length = slots_ + Context::MIN_CONTEXT_SLOTS; 1733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateInNewSpace(FixedArray::SizeFor(length), 1743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch eax, ebx, ecx, &gc, TAG_OBJECT); 1753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Get the function or sentinel from the stack. 1773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, Operand(esp, 1 * kPointerSize)); 1783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Get the serialized scope info from the stack. 1803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, Operand(esp, 2 * kPointerSize)); 1813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up the object header. 1833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Factory* factory = masm->isolate()->factory(); 1843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(FieldOperand(eax, HeapObject::kMapOffset), 1853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch factory->block_context_map()); 1863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(FieldOperand(eax, Context::kLengthOffset), 1873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Immediate(Smi::FromInt(length))); 1883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // If this block context is nested in the global context we get a smi 1903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // sentinel instead of a function. The block context should get the 1913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // canonical empty function of the global context as its closure which 1923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // we still have to look up. 1933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label after_sentinel; 1943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfNotSmi(ecx, &after_sentinel, Label::kNear); 1953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (FLAG_debug_code) { 1963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const char* message = "Expected 0 as a Smi sentinel"; 1973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ecx, 0); 1983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Assert(equal, message); 1993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, GlobalObjectOperand()); 2013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset)); 2023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, ContextOperand(ecx, Context::CLOSURE_INDEX)); 2033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&after_sentinel); 2043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up the fixed slots. 2063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ContextOperand(eax, Context::CLOSURE_INDEX), ecx); 2073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ContextOperand(eax, Context::PREVIOUS_INDEX), esi); 2083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ContextOperand(eax, Context::EXTENSION_INDEX), ebx); 2093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Copy the global object from the previous context. 2113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, ContextOperand(esi, Context::GLOBAL_INDEX)); 2123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ContextOperand(eax, Context::GLOBAL_INDEX), ebx); 2133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Initialize the rest of the slots to the hole value. 2153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (slots_ == 1) { 2163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ContextOperand(eax, Context::MIN_CONTEXT_SLOTS), 2173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch factory->the_hole_value()); 2183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 2193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, factory->the_hole_value()); 2203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = 0; i < slots_; i++) { 2213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ContextOperand(eax, i + Context::MIN_CONTEXT_SLOTS), ebx); 2223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Return and remove the on-stack parameters. 2263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(esi, eax); 2273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(2 * kPointerSize); 2283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Need to collect. Call into runtime system. 2303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&gc); 2313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kPushBlockContext, 2, 1); 2323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 2333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic void GenerateFastCloneShallowArrayCommon( 2363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler* masm, 2373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int length, 2383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FastCloneShallowArrayStub::Mode mode, 2393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label* fail) { 2403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Registers on entry: 2413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // 2423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ecx: boilerplate literal array. 2433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS); 2443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // All sizes here are multiples of kPointerSize. 2463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int elements_size = 0; 2473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (length > 0) { 2483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS 2493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ? FixedDoubleArray::SizeFor(length) 2503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch : FixedArray::SizeFor(length); 2513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int size = JSArray::kSize + elements_size; 2533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Allocate both the JS array and the elements array in one big 2553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // allocation. This avoids multiple limit checks. 2563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateInNewSpace(size, eax, ebx, edx, fail, TAG_OBJECT); 2573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Copy the JS array part. 2593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = 0; i < JSArray::kSize; i += kPointerSize) { 2603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if ((i != JSArray::kElementsOffset) || (length == 0)) { 2613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, FieldOperand(ecx, i)); 2623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(FieldOperand(eax, i), ebx); 2633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (length > 0) { 2673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Get hold of the elements array of the boilerplate and setup the 2683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // elements pointer in the resulting object. 2693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); 2703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lea(edx, Operand(eax, JSArray::kSize)); 2713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(FieldOperand(eax, JSArray::kElementsOffset), edx); 2723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Copy the elements array. 2743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (mode == FastCloneShallowArrayStub::CLONE_ELEMENTS) { 2753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = 0; i < elements_size; i += kPointerSize) { 2763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, FieldOperand(ecx, i)); 2773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(FieldOperand(edx, i), ebx); 2783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 2803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS); 2813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int i; 2823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) { 2833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, FieldOperand(ecx, i)); 2843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(FieldOperand(edx, i), ebx); 2853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch while (i < elements_size) { 2873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fld_d(FieldOperand(ecx, i)); 2883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fstp_d(FieldOperand(edx, i)); 2893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch i += kDoubleSize; 2903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(i == elements_size); 2923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 2953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 29780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { 29880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack layout on entry: 29980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // 30080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // [esp + kPointerSize]: constant elements. 30180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // [esp + (2 * kPointerSize)]: literal index. 30280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // [esp + (3 * kPointerSize)]: literals array. 30380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 30480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load boilerplate object into ecx and check if we need to create a 30580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // boilerplate. 30680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esp, 3 * kPointerSize)); 30780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, 2 * kPointerSize)); 30880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kPointerSize == 4); 30980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize == 1); 31080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 31180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size, 31280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize)); 31344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 31444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(ecx, factory->undefined_value()); 3153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label slow_case; 31680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &slow_case); 31780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FastCloneShallowArrayStub::Mode mode = mode_; 3193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ecx is boilerplate object. 3203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (mode == CLONE_ANY_ELEMENTS) { 3213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label double_elements, check_fast_elements; 3223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, FieldOperand(ecx, JSArray::kElementsOffset)); 3233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CheckMap(ebx, factory->fixed_cow_array_map(), 3243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &check_fast_elements, DONT_DO_SMI_CHECK); 3253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateFastCloneShallowArrayCommon(masm, 0, 3263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch COPY_ON_WRITE_ELEMENTS, &slow_case); 3273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(3 * kPointerSize); 3283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 3293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&check_fast_elements); 3303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CheckMap(ebx, factory->fixed_array_map(), 3313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &double_elements, DONT_DO_SMI_CHECK); 3323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateFastCloneShallowArrayCommon(masm, length_, 3333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CLONE_ELEMENTS, &slow_case); 3343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(3 * kPointerSize); 3353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 3363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&double_elements); 3373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch mode = CLONE_DOUBLE_ELEMENTS; 3383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Fall through to generate the code to handle double elements. 3393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 3403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 34180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 34280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const char* message; 34380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Handle<Map> expected_map; 3443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (mode == CLONE_ELEMENTS) { 34580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen message = "Expected (writable) fixed array"; 34644f0eee88ff00398ff7f715fab053374d808c90dSteve Block expected_map = factory->fixed_array_map(); 3473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else if (mode == CLONE_DOUBLE_ELEMENTS) { 3483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch message = "Expected (writable) fixed double array"; 3493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch expected_map = factory->fixed_double_array_map(); 35080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 3513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(mode == COPY_ON_WRITE_ELEMENTS); 35280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen message = "Expected copy-on-write fixed array"; 35344f0eee88ff00398ff7f715fab053374d808c90dSteve Block expected_map = factory->fixed_cow_array_map(); 35480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 35580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ecx); 35680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); 35780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), expected_map); 35880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Assert(equal, message); 35980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ecx); 36080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 36180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateFastCloneShallowArrayCommon(masm, length_, mode, &slow_case); 3633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Return and remove the on-stack parameters. 3643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(3 * kPointerSize); 365592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch 3663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&slow_case); 3673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); 3683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 369592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch 370592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch 3713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid FastCloneShallowObjectStub::Generate(MacroAssembler* masm) { 3723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Stack layout on entry: 3733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // 3743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // [esp + kPointerSize]: object literal flags. 3753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // [esp + (2 * kPointerSize)]: constant properties. 3763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // [esp + (3 * kPointerSize)]: literal index. 3773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // [esp + (4 * kPointerSize)]: literals array. 3783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 3793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load boilerplate object into ecx and check if we need to create a 3803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // boilerplate. 3813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label slow_case; 3823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, Operand(esp, 4 * kPointerSize)); 3833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(eax, Operand(esp, 3 * kPointerSize)); 3843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kPointerSize == 4); 3853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kSmiTagSize == 1); 3863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kSmiTag == 0); 3873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size, 3883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FixedArray::kHeaderSize)); 3893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Factory* factory = masm->isolate()->factory(); 3903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ecx, factory->undefined_value()); 3913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(equal, &slow_case); 3923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 3933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Check that the boilerplate contains only fast properties and we can 3943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // statically determine the instance size. 3953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int size = JSObject::kHeaderSize + length_ * kPointerSize; 3963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(eax, FieldOperand(ecx, HeapObject::kMapOffset)); 3973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movzx_b(eax, FieldOperand(eax, Map::kInstanceSizeOffset)); 3983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(eax, Immediate(size >> kPointerSizeLog2)); 3993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &slow_case); 4003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 4013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Allocate the JS object and copy header together with all in-object 4023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // properties from the boilerplate. 4033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateInNewSpace(size, eax, ebx, edx, &slow_case, TAG_OBJECT); 4043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = 0; i < size; i += kPointerSize) { 4053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, FieldOperand(ecx, i)); 4063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(FieldOperand(eax, i), ebx); 40780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 40880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 40980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameters. 4103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(4 * kPointerSize); 41180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 41280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow_case); 4133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kCreateObjectLiteralShallow, 4, 1); 41480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 41580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 41680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 41769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch// The stub expects its argument on the stack and returns its result in tos_: 41869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch// zero for false, and a non-zero value for true. 41980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ToBooleanStub::Generate(MacroAssembler* masm) { 4203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // This stub overrides SometimesSetsUpAFrame() to return false. That means 4213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // we cannot call anything that could cause a GC from this stub. 42269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label patch; 423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Factory* factory = masm->isolate()->factory(); 42469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch const Register argument = eax; 4253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const Register map = edx; 4263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 42769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!types_.IsEmpty()) { 42869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(argument, Operand(esp, 1 * kPointerSize)); 42969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // undefined -> false 43269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false); 433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Boolean -> its value 43569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false); 43669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true); 43780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 'null' -> false. 43969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false); 44080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 44169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(SMI)) { 44269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Smis: 0 -> false, all other -> true 44369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_smi; 44469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfNotSmi(argument, ¬_smi, Label::kNear); 44569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // argument contains the correct return value already. 44669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!tos_.is(argument)) { 44769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(tos_, argument); 44869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 44969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 45069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_smi); 45169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } else if (types_.NeedsMap()) { 45269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If we need a map later and have a Smi -> patch. 45369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfSmi(argument, &patch, Label::kNear); 45469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 45580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 45669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.NeedsMap()) { 45769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(map, FieldOperand(argument, HeapObject::kMapOffset)); 45869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 45969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.CanBeUndetectable()) { 46069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ test_b(FieldOperand(map, Map::kBitFieldOffset), 46169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 1 << Map::kIsUndetectable); 46269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Undetectable -> false. 46369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_undetectable; 46469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, ¬_undetectable, Label::kNear); 46569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, Immediate(0)); 46669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 46769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_undetectable); 46869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 46969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 47080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 47169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(SPEC_OBJECT)) { 47269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // spec object -> true. 47369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_js_object; 47469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); 47569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(below, ¬_js_object, Label::kNear); 47669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // argument contains the correct return value already. 47769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!tos_.is(argument)) { 47869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, Immediate(1)); 47969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 48069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 48169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_js_object); 48269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 48380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 48469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(STRING)) { 48569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // String value -> false iff empty. 48669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_string; 48769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); 48869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(above_equal, ¬_string, Label::kNear); 48969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(tos_, FieldOperand(argument, String::kLengthOffset)); 49069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); // the string length is OK as the return value 49169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_string); 49269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 49380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 49469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(HEAP_NUMBER)) { 49569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // heap number -> false iff +0, -0, or NaN. 49669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_heap_number, false_result; 49769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(map, factory->heap_number_map()); 49869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_equal, ¬_heap_number, Label::kNear); 49969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ fldz(); 50069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ fld_d(FieldOperand(argument, HeapNumber::kValueOffset)); 50169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ FCmp(); 50269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &false_result, Label::kNear); 50369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // argument contains the correct return value already. 50469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!tos_.is(argument)) { 50569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, Immediate(1)); 50669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 50769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 50869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&false_result); 50969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, Immediate(0)); 51069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 51169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_heap_number); 51269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 51369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 51469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&patch); 51569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch GenerateTypeTransition(masm); 51669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch} 51769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 51869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 5193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StoreBufferOverflowStub::Generate(MacroAssembler* masm) { 5203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // We don't allow a GC during a store buffer overflow so there is no need to 5213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // store the registers in any particular way, but we do have to store and 5223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // restore them. 5233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pushad(); 5243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (save_doubles_ == kSaveFPRegs) { 5253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CpuFeatures::Scope scope(SSE2); 5263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters)); 5273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = 0; i < XMMRegister::kNumRegisters; i++) { 5283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch XMMRegister reg = XMMRegister::from_code(i); 5293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movdbl(Operand(esp, i * kDoubleSize), reg); 5303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 5313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 5323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int argument_count = 1; 5333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 5343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch AllowExternalCallThatCantCauseGC scope(masm); 5353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ PrepareCallCFunction(argument_count, ecx); 5363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(Operand(esp, 0 * kPointerSize), 5373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Immediate(ExternalReference::isolate_address())); 5383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallCFunction( 5393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference::store_buffer_overflow_function(masm->isolate()), 5403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch argument_count); 5413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (save_doubles_ == kSaveFPRegs) { 5423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CpuFeatures::Scope scope(SSE2); 5433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = 0; i < XMMRegister::kNumRegisters; i++) { 5443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch XMMRegister reg = XMMRegister::from_code(i); 5453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movdbl(reg, Operand(esp, i * kDoubleSize)); 5463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 5473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters)); 5483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 5493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ popad(); 5503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(0); 5513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 5523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 5533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 55469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid ToBooleanStub::CheckOddball(MacroAssembler* masm, 55569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Type type, 55669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Heap::RootListIndex value, 55769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch bool result) { 55869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch const Register argument = eax; 55969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(type)) { 56069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If we see an expected oddball, return its ToBoolean value tos_. 56169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label different_value; 56269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ CompareRoot(argument, value); 56369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_equal, &different_value, Label::kNear); 56469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!result) { 56569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If we have to return zero, there is no way around clearing tos_. 56669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, Immediate(0)); 56769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } else if (!tos_.is(argument)) { 56869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If we have to return non-zero, we can re-use the argument if it is the 56969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // same register as the result, because we never see Smi-zero here. 57069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(tos_, Immediate(1)); 57169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 57269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ret(1 * kPointerSize); 57369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&different_value); 57469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 57569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch} 57669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 57769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 57869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) { 57969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ pop(ecx); // Get return address, operand is now on top of stack. 58069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ push(Immediate(Smi::FromInt(tos_.code()))); 58169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ push(Immediate(Smi::FromInt(types_.ToByte()))); 58269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ push(ecx); // Push return address. 58369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Patch the caller to an appropriate specialized stub and return the 58469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // operation result to the caller of the stub. 58569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ TailCallExternalReference( 58669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()), 58769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 3, 58869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 1); 58980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 59080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 59180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5928b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochclass FloatingPointHelper : public AllStatic { 5938b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch public: 5948b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch enum ArgLocation { 5958b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch ARGS_ON_STACK, 5968b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch ARGS_IN_REGISTERS 5978b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch }; 59880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5998b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Code pattern for loading a floating point value. Input value must 6008b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // be either a smi or a heap number object (fp value). Requirements: 6018b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operand in register number. Returns operand as floating point number 6028b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // on FPU stack. 6038b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadFloatOperand(MacroAssembler* masm, Register number); 60480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6058b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Code pattern for loading floating point values. Input values must 6068b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // be either smi or heap number objects (fp values). Requirements: 6078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax. 6088b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Returns operands as floating point numbers on FPU stack. 6098b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadFloatOperands(MacroAssembler* masm, 6108b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register scratch, 6118b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch ArgLocation arg_location = ARGS_ON_STACK); 61280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6138b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Similar to LoadFloatOperand but assumes that both operands are smis. 6148b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Expects operands in edx, eax. 6158b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadFloatSmis(MacroAssembler* masm, Register scratch); 616b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6178b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Test if operands are smi or number objects (fp). Requirements: 6188b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operand_1 in eax, operand_2 in edx; falls through on float 6198b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operands, jumps to the non_float label otherwise. 6208b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void CheckFloatOperands(MacroAssembler* masm, 6218b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* non_float, 6228b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Register scratch); 623b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6248b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Checks that the two floating point numbers on top of the FPU stack 6258b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // have int32 values. 6268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void CheckFloatOperandsAreInt32(MacroAssembler* masm, 6278b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* non_int32); 628b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6298b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Takes the operands in edx and eax and loads them as integers in eax 6308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // and ecx. 6318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadUnknownsAsIntegers(MacroAssembler* masm, 6328b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch bool use_sse3, 6338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* operand_conversion_failure); 634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Must only be called after LoadUnknownsAsIntegers. Assumes that the 6368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // operands are pushed on the stack, and that their conversions to int32 6378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // are in eax and ecx. Checks that the original numbers were in the int32 6388b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // range. 6398b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void CheckLoadedIntegersWereInt32(MacroAssembler* masm, 6408b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch bool use_sse3, 6418b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* not_int32); 642b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6438b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Assumes that operands are smis or heap numbers and loads them 6448b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // into xmm0 and xmm1. Operands are in edx and eax. 6458b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Leaves operands unchanged. 6468b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadSSE2Operands(MacroAssembler* masm); 647b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6488b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Test if operands are numbers (smi or HeapNumber objects), and load 6498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // them into xmm0 and xmm1 if they are. Jump to label not_numbers if 6508b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // either operand is not a number. Operands are in edx and eax. 6518b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Leaves operands unchanged. 6528b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers); 653b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6548b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Similar to LoadSSE2Operands but assumes that both operands are smis. 6558b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Expects operands in edx, eax. 6568b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch static void LoadSSE2Smis(MacroAssembler* masm, Register scratch); 657b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Checks that the two floating point numbers loaded into xmm0 and xmm1 659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // have int32 values. 660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch static void CheckSSE2OperandsAreInt32(MacroAssembler* masm, 661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* non_int32, 662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch); 663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}; 664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Get the integer part of a heap number. Surprisingly, all this bit twiddling 667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// is faster than using the built-in instructions on floating point registers. 668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the 669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// trashed registers. 670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void IntegerConvert(MacroAssembler* masm, 671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register source, 672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch bool use_sse3, 673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* conversion_failure) { 674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); 675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done, right_exponent, normal_exponent; 676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch = ebx; 677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch2 = edi; 678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get exponent word. 679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); 680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get exponent alone in scratch2. 681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch2, scratch); 682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(scratch2, HeapNumber::kExponentMask); 683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (use_sse3) { 684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CpuFeatures::Scope scope(SSE3); 685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check whether the exponent is too big for a 64 bit signed integer. 686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch static const uint32_t kTooBigExponent = 687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; 6883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(scratch2, Immediate(kTooBigExponent)); 689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(greater_equal, conversion_failure); 690257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Load x87 register with heap number. 691257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); 692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Reserve space for 64 bit answer. 6933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(esp, Immediate(sizeof(uint64_t))); // Nolint. 694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Do conversion, which cannot fail because we checked the exponent. 695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fisttp_d(Operand(esp, 0)); 696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, Operand(esp, 0)); // Load low word of answer into ecx. 6973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(esp, Immediate(sizeof(uint64_t))); // Nolint. 698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 699257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Load ecx with zero. We use this either for the final shift or 700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // for the answer. 7013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(ecx, ecx); 702257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check whether the exponent matches a 32 bit signed int that cannot be 703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // represented by a Smi. A non-smi 32 bit integer is 1.xxx * 2^30 so the 704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // exponent is 30 (biased). This is the exponent that we are fastest at and 705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // also the highest exponent we can handle here. 706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const uint32_t non_smi_exponent = 707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; 7083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(scratch2, Immediate(non_smi_exponent)); 709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If we have a match of the int32-but-not-Smi exponent then skip some 710257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // logic. 71169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(equal, &right_exponent, Label::kNear); 712257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If the exponent is higher than that then go to slow case. This catches 713257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // numbers that don't fit in a signed int32, infinities and NaNs. 71469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(less, &normal_exponent, Label::kNear); 715257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 716257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch { 717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle a big exponent. The only reason we have this code is that the 718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // >>> operator has a tendency to generate numbers with an exponent of 31. 719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const uint32_t big_non_smi_exponent = 720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift; 7213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(scratch2, Immediate(big_non_smi_exponent)); 722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, conversion_failure); 723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We have the big exponent, typically from >>>. This means the number is 724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // in the range 2^31 to 2^32 - 1. Get the top bits of the mantissa. 725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch2, scratch); 726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(scratch2, HeapNumber::kMantissaMask); 727257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Put back the implicit 1. 728257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ or_(scratch2, 1 << HeapNumber::kExponentShift); 729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Shift up the mantissa bits to take up the space the exponent used to 730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // take. We just orred in the implicit bit so that took care of one and 731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // we want to use the full unsigned range so we subtract 1 bit from the 732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // shift distance. 733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1; 734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shl(scratch2, big_shift_distance); 735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get the second half of the double. 736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset)); 737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Shift down 21 bits to get the most significant 11 bits or the low 738257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // mantissa word. 739257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(ecx, 32 - big_shift_distance); 7403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ or_(ecx, scratch2); 741257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We have the answer in ecx, but we may need to negate it. 7423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(scratch, scratch); 74369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(positive, &done, Label::kNear); 744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ neg(ecx); 74569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&done, Label::kNear); 746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 747257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 748257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&normal_exponent); 749257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Exponent word in scratch, exponent part of exponent word in scratch2. 750257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Zero in ecx. 751257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We know the exponent is smaller than 30 (biased). If it is less than 7523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, i.e. 753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // it rounds to zero. 754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const uint32_t zero_exponent = 755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift; 7563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(scratch2, Immediate(zero_exponent)); 757257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // ecx already has a Smi zero. 75869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(less, &done, Label::kNear); 759257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 760257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We have a shifted exponent between 0 and 30 in scratch2. 761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(scratch2, HeapNumber::kExponentShift); 762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, Immediate(30)); 7633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(ecx, scratch2); 764257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&right_exponent); 766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Here ecx is the shift, scratch is the exponent word. 767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get the top bits of the mantissa. 768257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(scratch, HeapNumber::kMantissaMask); 769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Put back the implicit 1. 770257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ or_(scratch, 1 << HeapNumber::kExponentShift); 771257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Shift up the mantissa bits to take up the space the exponent used to 772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // take. We have kExponentShift + 1 significant bits int he low end of the 773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // word. Shift them to the top bits. 774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2; 775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shl(scratch, shift_distance); 776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Get the second half of the double. For some exponents we don't 777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // actually need this because the bits get shifted out again, but 778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // it's probably slower to test than just to do it. 779257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset)); 780257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Shift down 22 bits to get the most significant 10 bits or the low 781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // mantissa word. 782257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(scratch2, 32 - shift_distance); 7833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ or_(scratch2, scratch); 784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Move down according to the exponent. 785257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr_cl(scratch2); 786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Now the unsigned answer is in scratch2. We need to move it to ecx and 787257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // we may need to fix the sign. 788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label negative; 7893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(ecx, ecx); 790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset)); 791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(greater, &negative, Label::kNear); 792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, scratch2); 793257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&negative); 7953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(ecx, scratch2); 796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&done); 797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 799257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 8013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid UnaryOpStub::PrintName(StringStream* stream) { 802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const char* op_name = Token::Name(op_); 803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const char* overwrite_name = NULL; // Make g++ happy. 804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (mode_) { 805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; 806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; 807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 8083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("UnaryOpStub_%s_%s_%s", 8093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch op_name, 8103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch overwrite_name, 8113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch UnaryOpIC::GetName(operand_type_)); 812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 814257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 816257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::Generate(MacroAssembler* masm) { 817257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (operand_type_) { 818257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::UNINITIALIZED: 819257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 820257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::SMI: 822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStub(masm); 823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::HEAP_NUMBER: 825257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStub(masm); 826257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::GENERIC: 828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStub(masm); 829257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 830257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 832257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 834257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 835257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(ecx); // Save return address. 8363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 8373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(eax); // the operand 838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(Immediate(Smi::FromInt(op_))); 8393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(Immediate(Smi::FromInt(mode_))); 840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(Immediate(Smi::FromInt(operand_type_))); 841257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 842257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(ecx); // Push return address. 843257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 844257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Patch the caller to an appropriate specialized stub and return the 845257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // operation result to the caller of the stub. 846257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ TailCallExternalReference( 8473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1); 848257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 849257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 850257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 852257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 853257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStubSub(masm); 856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 858257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStubBitNot(masm); 859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 860257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 861257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 862257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 863257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) { 867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, undo, slow; 868257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, 869257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::kNear, Label::kNear, Label::kNear); 870257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&undo); 871257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeUndo(masm); 872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 873257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 876257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 878257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) { 879257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi; 880257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi); 881257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 882257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 883257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 884257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 886257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, 887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* non_smi, 888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* undo, 889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* slow, 890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance non_smi_near, 891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance undo_near, 892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance slow_near) { 893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check whether the value is a smi. 8943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, non_smi, non_smi_near); 895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // We can't handle -0 with smis, so use a type transition for that case. 8973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(eax, eax); 898257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, slow, slow_near); 899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Try optimistic subtraction '0 - value', saving operand in eax for undo. 9013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edx, eax); 902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(0)); 9033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(eax, edx); 904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(overflow, undo, undo_near); 905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeBitNot( 910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* non_smi, 912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance non_smi_near) { 913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check whether the value is a smi. 9143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, non_smi, non_smi_near); 915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Flip bits and revert inverted smi-tag. 917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ not_(eax); 918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(eax, ~kSmiTagMask); 919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) { 9243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(eax, edx); 925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 932257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStubSub(masm); 933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 934257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStubBitNot(masm); 936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 937257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 938257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 939257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 943257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) { 944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, undo, slow, call_builtin; 945257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &non_smi, &undo, &call_builtin, Label::kNear); 946257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 947257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeSub(masm, &slow); 948257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&undo); 949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeUndo(masm); 950257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_builtin); 953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubBitNot( 958257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm) { 959257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow; 960257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); 961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeBitNot(masm, &slow); 963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 964257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, 969257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* slow) { 970257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); 971257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(edx, masm->isolate()->factory()->heap_number_map()); 972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, slow); 973257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 974257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (mode_ == UNARY_OVERWRITE) { 975257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset), 976257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Immediate(HeapNumber::kSignMask)); // Flip sign. 977257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 9783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edx, eax); 979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // edx: operand 980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label slow_allocate_heapnumber, heapnumber_allocated; 982257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber); 98369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&heapnumber_allocated, Label::kNear); 984257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 985257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow_allocate_heapnumber); 9863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 9873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FrameScope scope(masm, StackFrame::INTERNAL); 9883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(edx); 9893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallRuntime(Runtime::kNumberAlloc, 0); 9903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(edx); 9913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&heapnumber_allocated); 994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // eax: allocated 'empty' number 995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); 996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ xor_(ecx, HeapNumber::kSignMask); // Flip sign. 997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx); 998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset)); 999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); 1000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 1001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 1002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm, 1006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* slow) { 1007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); 1008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(edx, masm->isolate()->factory()->heap_number_map()); 1009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, slow); 1010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Convert the heap number in eax to an untagged integer in ecx. 1012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), slow); 1013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Do the bitwise operation and check if the result fits in a smi. 1015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label try_float; 1016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ not_(ecx); 1017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(ecx, 0xc0000000); 1018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(sign, &try_float, Label::kNear); 1019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Tag the result as a smi and we're done. 1021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTagSize == 1); 1022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(eax, Operand(ecx, times_2, kSmiTag)); 1023257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 1024257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1025257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Try to store the result in a heap number. 1026257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&try_float); 1027257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (mode_ == UNARY_NO_OVERWRITE) { 1028257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label slow_allocate_heapnumber, heapnumber_allocated; 1029257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(ebx, eax); 1030257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ AllocateHeapNumber(eax, edx, edi, &slow_allocate_heapnumber); 1031257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&heapnumber_allocated); 1032257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow_allocate_heapnumber); 10343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 10353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FrameScope scope(masm, StackFrame::INTERNAL); 10363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Push the original HeapNumber on the stack. The integer value can't 10373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // be stored since it's untagged and not in the smi range (so we can't 10383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // smi-tag it). We'll recalculate the value after the GC instead. 10393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(ebx); 10403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallRuntime(Runtime::kNumberAlloc, 0); 10413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // New HeapNumber is in eax. 10423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(edx); 10433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 1044257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // IntegerConvert uses ebx and edi as scratch registers. 1045257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // This conversion won't go slow-case. 1046257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch IntegerConvert(masm, edx, CpuFeatures::IsSupported(SSE3), slow); 1047257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ not_(ecx); 1048257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1049257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&heapnumber_allocated); 1050257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 1051257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1052257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 10533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(xmm0, ecx); 1054257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1055257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 1056257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(ecx); 1057257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fild_s(Operand(esp, 0)); 1058257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(ecx); 1059257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1060257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 1061257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 1062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1063257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1064257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1065257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 1066257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) { 1067257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 1068257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 1069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStubSub(masm); 1070257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 1071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 1072257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStubBitNot(masm); 1073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 1074257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 1075257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 1076257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 1077257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1078257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1079257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1080257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) { 1081257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, undo, slow; 1082257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, Label::kNear); 1083257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 1084257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeSub(masm, &slow); 1085257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&undo); 1086257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeUndo(masm); 1087257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 1088257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 1089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1090257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1092257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) { 1093257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow; 1094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); 1095257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 1096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeBitNot(masm, &slow); 1097257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 1098257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 1099257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1100257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) { 1103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle the slow case by jumping to the corresponding JavaScript builtin. 1104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(ecx); // pop return address. 1105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(eax); 1106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(ecx); // push return address 1107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 1108257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 1109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION); 1110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 1111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 1112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); 1113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 1114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 1115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 1116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 1117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 1121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(ecx); // Save return address. 1122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(edx); 1123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(eax); 1124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Left and right arguments are now on top. 1125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Push this stub's key. Although the operation and the type info are 1126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // encoded into the key, the encoding is opaque, so push them too. 1127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(MinorKey()))); 1128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(op_))); 1129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(operands_type_))); 1130b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(ecx); // Push return address. 1132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Patch the caller to an appropriate specialized stub and return the 1134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // operation result to the caller of the stub. 1135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TailCallExternalReference( 1136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ExternalReference(IC_Utility(IC::kBinaryOp_Patch), 113744f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()), 1138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5, 1139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1); 1140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1141b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1142b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1143b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// Prepare for a type transition runtime call when the args are already on 1144b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// the stack, under the return address. 1145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) { 1146b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(ecx); // Save return address. 1147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Left and right arguments are already on top of the stack. 1148b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Push this stub's key. Although the operation and the type info are 1149b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // encoded into the key, the encoding is opaque, so push them too. 1150b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(MinorKey()))); 1151b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(op_))); 1152b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(Smi::FromInt(operands_type_))); 1153b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1154b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(ecx); // Push return address. 1155b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1156b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Patch the caller to an appropriate specialized stub and return the 1157b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // operation result to the caller of the stub. 1158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TailCallExternalReference( 1159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ExternalReference(IC_Utility(IC::kBinaryOp_Patch), 116044f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()), 1161b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5, 1162b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1); 1163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1165b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::Generate(MacroAssembler* masm) { 11673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Explicitly allow generation of nested stubs. It is safe here because 11683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // generation code does not use any raw pointers. 11693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch AllowStubCallsScope allow_stub_calls(masm, true); 11703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (operands_type_) { 1172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::UNINITIALIZED: 1173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 1174b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::SMI: 1176b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateSmiStub(masm); 1177b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::INT32: 1179b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateInt32Stub(masm); 1180b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::HEAP_NUMBER: 1182b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapNumberStub(masm); 1183b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::ODDBALL: 118544f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateOddballStub(masm); 118644f0eee88ff00398ff7f715fab053374d808c90dSteve Block break; 1187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::BOTH_STRING: 1188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateBothStringStub(masm); 1189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 1190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::STRING: 1191b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateStringStub(masm); 1192b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::GENERIC: 1194b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateGeneric(masm); 1195b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1196b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1197b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1198b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1200b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 12023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid BinaryOpStub::PrintName(StringStream* stream) { 1203b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const char* op_name = Token::Name(op_); 1204b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const char* overwrite_name; 1205b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode_) { 1206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: overwrite_name = "Alloc"; break; 1207b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; 1208b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; 1209b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: overwrite_name = "UnknownOverwrite"; break; 1210b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 12113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("BinaryOpStub_%s_%s_%s", 12123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch op_name, 12133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch overwrite_name, 12143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch BinaryOpIC::GetName(operands_type_)); 1215b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1216b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1217b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiCode( 1219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 1220b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* slow, 1221b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { 1222b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 1. Move arguments into edx, eax except for DIV and MOD, which need the 1223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // dividend in eax and edx free for the division. Use eax, ebx for those. 1224b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment load_comment(masm, "-- Load arguments"); 1225b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register left = edx; 1226b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register right = eax; 1227b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ == Token::DIV || op_ == Token::MOD) { 1228b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch left = eax; 1229b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch right = ebx; 1230b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, eax); 1231b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, edx); 1232b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1233b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1234b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1235b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 2. Prepare the smi check of both operands by oring them together. 1236b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment smi_check_comment(masm, "-- Smi check arguments"); 1237b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_smis; 1238b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register combined = ecx; 1239b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(!left.is(combined) && !right.is(combined)); 1240b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1241b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1242b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Perform the operation into eax and smi check the result. Preserve 1243b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax in case the result is not a smi. 1244b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(!left.is(ecx) && !right.is(ecx)); 1245b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, right); 12463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ or_(right, left); // Bitwise or is commutative. 1247b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch combined = right; 1248b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1249b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1250b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1251b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1252b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1253b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1254b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1255b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1256b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(combined, right); 12583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ or_(combined, left); 1259b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1260b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1262b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Move the right operand into ecx for the shift operation, use eax 1265b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // for the smi check register. 1266b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(!left.is(ecx) && !right.is(ecx)); 1267b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, right); 12683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ or_(right, left); 1269b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch combined = right; 1270b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1271b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1272b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1273b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1274b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1275b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1276b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 3. Perform the smi check of the operands. 1277b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTag == 0); // Adjust zero check if not the case. 12783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(combined, ¬_smis); 1279b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1280b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 4. Operands are both smis, perform the operation leaving the result in 1281b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax and check the result if necessary. 1282b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment perform_smi(masm, "-- Perform smi operation"); 1283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label use_fp_on_smis; 1284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Nothing to do. 1287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1290b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(right.is(eax)); 12913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(right, left); // Bitwise xor is commutative. 1292b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1293b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1294b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1295b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(right.is(eax)); 12963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(right, left); // Bitwise and is commutative. 1297b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1298b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1299b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1300b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Remove tags from operands (but keep sign). 1301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(left); 1302b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(ecx); 1303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Perform the operation. 1304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ shl_cl(left); 1305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check that the *signed* result fits in a smi. 1306b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(left, 0xc0000000); 1307257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(sign, &use_fp_on_smis); 1308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag the result and store it in register eax. 1309b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(left); 1310b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, left); 1311b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1312b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1313b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1314b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Remove tags from operands (but keep sign). 1315b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(left); 1316b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(ecx); 1317b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Perform the operation. 1318b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sar_cl(left); 1319b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag the result and store it in register eax. 1320b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(left); 1321b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, left); 1322b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1323b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1324b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1325b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Remove tags from operands (but keep sign). 1326b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(left); 1327b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(ecx); 1328b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Perform the operation. 1329b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ shr_cl(left); 1330b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check that the *unsigned* result fits in a smi. 1331b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Neither of the two high-order bits can be set: 1332b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // - 0x80000000: high bit would be lost when smi tagging. 1333b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // - 0x40000000: this number would convert to negative when 1334b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Smi tagging these two cases can only happen with shifts 1335b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // by 0 or 1 when handed a valid smi. 1336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(left, Immediate(0xc0000000)); 1337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &use_fp_on_smis); 1338b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag the result and store it in register eax. 1339b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(left); 1340b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, left); 1341b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1342b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1343b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1344b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(right.is(eax)); 13453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(right, left); // Addition is commutative. 1346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(overflow, &use_fp_on_smis); 1347b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1348b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1349b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 13503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(left, right); 1351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(overflow, &use_fp_on_smis); 1352b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, left); 1353b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1354b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1355b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1356b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the smi tag is 0 we can just leave the tag on one operand. 1357b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTag == 0); // Adjust code below if not the case. 1358b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // We can't revert the multiplication if the result is not a smi 1359b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // so save the right operand. 1360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, right); 1361b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Remove tag from one of the operands (but keep sign). 1362b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(right); 1363b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Do multiplication. 13643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ imul(right, left); // Multiplication is commutative. 1365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(overflow, &use_fp_on_smis); 1366b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for negative zero result. Use combined = left | right. 1367b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ NegativeZeroTest(right, combined, &use_fp_on_smis); 1368b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1369b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1370b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1371b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // We can't revert the division if the result is not a smi so 1372b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // save the left operand. 1373b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edi, left); 1374b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for 0 divisor. 13753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(right, right); 1376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &use_fp_on_smis); 1377b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Sign extend left into edx:eax. 1378b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(left.is(eax)); 1379b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cdq(); 1380b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Divide edx:eax by right. 1381b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ idiv(right); 1382b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for the corner case of dividing the most negative smi by 1383b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // -1. We cannot use the overflow flag, since it is not set by idiv 1384b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // instruction. 1385b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); 1386b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(eax, 0x40000000); 1387b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(equal, &use_fp_on_smis); 1388b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for negative zero result. Use combined = left | right. 1389b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ NegativeZeroTest(eax, combined, &use_fp_on_smis); 1390b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check that the remainder is zero. 13913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(edx, edx); 1392b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &use_fp_on_smis); 1393b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag the result and store it in register eax. 1394b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(eax); 1395b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1396b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1397b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1398b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for 0 divisor. 13993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(right, right); 1400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, ¬_smis); 1401b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1402b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Sign extend left into edx:eax. 1403b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(left.is(eax)); 1404b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cdq(); 1405b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Divide edx:eax by right. 1406b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ idiv(right); 1407b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for negative zero result. Use combined = left | right. 1408b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ NegativeZeroTest(edx, combined, slow); 1409b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Move remainder to register eax. 1410b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, edx); 1411b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1412b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1413b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1414b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1415b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1416b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1417b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 5. Emit return of result in eax. Some operations have registers pushed. 1418b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1419b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1420b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1421b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1422b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1423b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1424b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1425b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1426b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1427b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1428b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1429b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1430b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1431b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1432b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); 1433b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1434b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1435b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1436b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1437b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1438b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 6. For some operations emit inline code to perform floating point 1439b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // operations on known smis (e.g., if the result of the operation 1440b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // overflowed the smi range). 1441b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (allow_heapnumber_results == NO_HEAPNUMBER_RESULTS) { 1442b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&use_fp_on_smis); 1443b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1444b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Undo the effects of some operations, and some register moves. 1445b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1446b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // The arguments are saved on the stack, and only used from there. 1447b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1448b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1449b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Revert right = right + left. 14503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(right, left); 1451b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1452b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1453b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Revert left = left - right. 14543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(left, right); 1455b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1456b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1457b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Right was clobbered but a copy is in ebx. 1458b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(right, ebx); 1459b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1460b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1461b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Left was clobbered but a copy is in edi. Right is in ebx for 1462b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // division. They should be in eax, ebx for jump to not_smi. 1463b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, edi); 1464b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1465b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1466b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // No other operators jump to use_fp_on_smis. 1467b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1468b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1469b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(¬_smis); 1470b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1471b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS); 1472b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SHL: 1474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SHR: { 1475b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment perform_float(masm, "-- Perform float operation on smis"); 1476b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&use_fp_on_smis); 1477b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Result we want is in left == edx, so we can put the allocated heap 1478b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // number in eax. 1479b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, ecx, ebx, slow); 1480b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Store the result in the HeapNumber and return. 1481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // It's OK to overwrite the arguments on the stack because we 1482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // are about to return. 1483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (op_ == Token::SHR) { 1484b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), left); 1485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(Operand(esp, 2 * kPointerSize), Immediate(0)); 1486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fild_d(Operand(esp, 1 * kPointerSize)); 1487b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 1489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT_EQ(Token::SHL, op_); 1490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 14923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(xmm0, left); 1493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 1495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), left); 1496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fild_s(Operand(esp, 1 * kPointerSize)); 1497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 1499b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 1501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 1502b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1503b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1504b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1505b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1506b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1507b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: { 1508b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment perform_float(masm, "-- Perform float operation on smis"); 1509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&use_fp_on_smis); 1510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Restore arguments to edx, eax. 1511b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1512b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1513b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Revert right = right + left. 15143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(right, left); 1515b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1516b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1517b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Revert left = left - right. 15183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(left, right); 1519b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1520b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1521b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Right was clobbered but a copy is in ebx. 1522b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(right, ebx); 1523b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1524b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1525b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Left was clobbered but a copy is in edi. Right is in ebx for 1526b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // division. 1527b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, edi); 1528b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, right); 1529b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1530b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(ecx, ebx, no_reg, slow); 15348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1536b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Smis(masm, ebx); 1537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1538b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ addsd(xmm0, xmm1); break; 1539b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ subsd(xmm0, xmm1); break; 1540b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ mulsd(xmm0, xmm1); break; 1541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ divsd(xmm0, xmm1); break; 1542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0); 1545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // SSE2 not available, use FPU. 1546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadFloatSmis(masm, ebx); 1547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ faddp(1); break; 1549b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ fsubp(1); break; 1550b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ fmulp(1); break; 1551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ fdivp(1); break; 1552b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset)); 1555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, ecx); 1557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1566b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // 7. Non-smi operands, fall out to the non-smi code with the operands in 1567b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // edx and eax. 1568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Comment done_comment(masm, "-- Enter non-smi code"); 1569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_smis); 1570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1575b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Right operand is saved in ecx and eax was destroyed by the smi 1576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // check. 1577b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, ecx); 1578b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1580b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1581b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1582b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Operands are in eax, ebx at this point. 1583b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, eax); 1584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, ebx); 1585b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1586b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1587b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1588b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1589b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1590b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1591b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1592b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1593257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 1594b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label call_runtime; 1595b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1596b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1597b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1598b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1599b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1600b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1601b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1602b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1603b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1604b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1605b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1606b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1607b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1608b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1609b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1610b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1611b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1612b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1613b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1614b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (result_type_ == BinaryOpIC::UNINITIALIZED || 1616257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch result_type_ == BinaryOpIC::SMI) { 1617b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateSmiCode(masm, &call_runtime, NO_HEAPNUMBER_RESULTS); 1618b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1619b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 1620b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1621b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&call_runtime); 1622b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1623b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1624b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1625b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1626b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1627b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 1628b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1629b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1630b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1632b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1633b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1635b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1636b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransitionWithSavedArgs(masm); 1637b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1638b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1639b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1640b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1641b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1642b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1643b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { 1645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(operands_type_ == BinaryOpIC::STRING); 1646b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(op_ == Token::ADD); 16471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Try to add arguments as strings, otherwise, transition to the generic 1648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // BinaryOpIC type. 16491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateAddStrings(masm); 1650b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 1651b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1652b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1653b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { 1655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label call_runtime; 1656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); 1657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(op_ == Token::ADD); 1658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If both arguments are strings, call the string add stub. 1659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Otherwise, do a transition. 1660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 1662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = edx; 1663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = eax; 1664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Test if left operand is a string. 166669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfSmi(left, &call_runtime, Label::kNear); 1667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); 166869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(above_equal, &call_runtime, Label::kNear); 1669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Test if right operand is a string. 167169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfSmi(right, &call_runtime, Label::kNear); 1672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); 167369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(above_equal, &call_runtime, Label::kNear); 1674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); 1676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateRegisterArgsPush(masm); 1677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ TailCallStub(&string_add_stub); 1678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_runtime); 1680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 1681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { 1685b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label call_runtime; 1686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(operands_type_ == BinaryOpIC::INT32); 1687b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1688b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Floating point case. 1689b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1690b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1691b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1692b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1693b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: { 1694b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 1695b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_int32; 16968b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1697b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1698b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 1699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); 1700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ addsd(xmm0, xmm1); break; 1702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ subsd(xmm0, xmm1); break; 1703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ mulsd(xmm0, xmm1); break; 1704b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ divsd(xmm0, xmm1); break; 1705b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1706b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1707b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check result type if it is currently Int32. 1708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (result_type_ <= BinaryOpIC::INT32) { 1709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvttsd2si(ecx, Operand(xmm0)); 17103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(xmm2, ecx); 1711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm0, xmm2); 1712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, ¬_int32); 1713b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(carry, ¬_int32); 1714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1715b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &call_runtime); 1716b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1717b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // SSE2 not available, use FPU. 1719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); 1720b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadFloatOperands( 1721b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch masm, 1722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ecx, 1723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::ARGS_IN_REGISTERS); 1724b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckFloatOperandsAreInt32(masm, ¬_int32); 1725b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1726b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ faddp(1); break; 1727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ fsubp(1); break; 1728b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ fmulp(1); break; 1729b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ fdivp(1); break; 1730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label after_alloc_failure; 1733b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &after_alloc_failure); 1734b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1735b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1736b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&after_alloc_failure); 1737b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ffree(); 1738b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&call_runtime); 1739b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 1742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_int32); 1743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 1744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: { 1748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // For MOD we go directly to runtime in the non-smi case. 1749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1752b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1754b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1756b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: { 1757b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 1759b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_int32; 1760b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label non_smi_result; 1761b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch /* { 1762b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 1764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); 1765b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch }*/ 1766b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadUnknownsAsIntegers(masm, 1767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch use_sse3_, 1768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ¬_floats); 1769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_, 1770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ¬_int32); 1771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 17723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch case Token::BIT_OR: __ or_(eax, ecx); break; 17733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch case Token::BIT_AND: __ and_(eax, ecx); break; 17743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch case Token::BIT_XOR: __ xor_(eax, ecx); break; 1775b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: __ sar_cl(eax); break; 1776b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: __ shl_cl(eax); break; 1777b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: __ shr_cl(eax); break; 1778b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1780b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ == Token::SHR) { 1781b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result is non-negative and fits in a smi. 1782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(eax, Immediate(0xc0000000)); 1783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &call_runtime); 1784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1785b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result fits in a smi. 1786b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(eax, 0xc0000000); 178769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(negative, &non_smi_result, Label::kNear); 1788b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1789b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag smi result and return. 1790b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(eax); 1791b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1792b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1793b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // All ops except SHR return a signed int32 that we load in 1794b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // a HeapNumber. 1795b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ != Token::SHR) { 1796b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&non_smi_result); 1797b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number if needed. 17983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, eax); // ebx: result 1799257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label skip_allocation; 1800b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode_) { 1801b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: 1802b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: 1803b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the operand was an object, we skip the 1804b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 1805b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 1806b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1 * kPointerSize : 2 * kPointerSize)); 18073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 1808b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fall through! 1809b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: 1810b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 1811b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 1812b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1813b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1814b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1815b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Store the result in the HeapNumber and return. 18168b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1817b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 18183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(xmm0, ebx); 1819b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1820b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1821b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ebx); 1822b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fild_s(Operand(esp, 1 * kPointerSize)); 1823b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1824b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1825b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1826b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1827b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1828b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 1829b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_int32); 1830b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransitionWithSavedArgs(masm); 1831b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1832b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1833b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); break; 1834b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1835b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1836b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If an allocation fails, or SHR or MOD hit a hard case, 1837b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // use the runtime system to get the correct result. 1838b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&call_runtime); 1839b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1840b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1843b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 1844b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1845b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1846b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1847b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 1848b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 1852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 1854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1855b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 1856b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1857b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 1858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 1860b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1861b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1862b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 1863b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1864b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1865b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 1866b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1867b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1868b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 1869b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1870b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1871b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 1872b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1873b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1874b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 1875b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1876b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 1877b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 1878b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1879b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 1880b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 1881b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1882b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1883b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1884b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { 188644f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (op_ == Token::ADD) { 188744f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Handle string addition here, because it is the only operation 188844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // that does not do a ToNumber conversion on the operands. 188944f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateAddStrings(masm); 189044f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 189144f0eee88ff00398ff7f715fab053374d808c90dSteve Block 1892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Factory* factory = masm->isolate()->factory(); 1893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 189444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Convert odd ball arguments to numbers. 1895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label check, done; 1896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(edx, factory->undefined_value()); 1897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &check, Label::kNear); 189844f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (Token::IsBitOp(op_)) { 18993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(edx, edx); 190044f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 1901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edx, Immediate(factory->nan_value())); 190244f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 1903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 190444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&check); 1905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(eax, factory->undefined_value()); 1906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &done, Label::kNear); 190744f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (Token::IsBitOp(op_)) { 19083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(eax, eax); 190944f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 1910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(eax, Immediate(factory->nan_value())); 191144f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 191244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&done); 191344f0eee88ff00398ff7f715fab053374d808c90dSteve Block 191444f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateHeapNumberStub(masm); 191544f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 191644f0eee88ff00398ff7f715fab053374d808c90dSteve Block 191744f0eee88ff00398ff7f715fab053374d808c90dSteve Block 1918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 1919b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label call_runtime; 1920b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1921b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Floating point case. 1922b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1923b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 1924b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 1925b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 1926b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: { 1927b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 19288b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 1929b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 1930b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 1931b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1932b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1933b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ addsd(xmm0, xmm1); break; 1934b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ subsd(xmm0, xmm1); break; 1935b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ mulsd(xmm0, xmm1); break; 1936b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ divsd(xmm0, xmm1); break; 1937b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1938b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1939b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &call_runtime); 1940b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1941b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1942b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // SSE2 not available, use FPU. 1943b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); 1944b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadFloatOperands( 1945b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch masm, 1946b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ecx, 1947b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::ARGS_IN_REGISTERS); 1948b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 1949b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ faddp(1); break; 1950b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ fsubp(1); break; 1951b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ fmulp(1); break; 1952b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ fdivp(1); break; 1953b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1954b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1955b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label after_alloc_failure; 1956b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &after_alloc_failure); 1957b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1958b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 1959b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&after_alloc_failure); 1960b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ffree(); 1961b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&call_runtime); 1962b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1963b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1964b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 1965b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransition(masm); 1966b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1967b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1968b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1969b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: { 1970b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // For MOD we go directly to runtime in the non-smi case. 1971b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 1972b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1973b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 1974b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 1975b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 1976b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 1977b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 1978b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: { 1979b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 1980b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 1981b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label non_smi_result; 1982b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadUnknownsAsIntegers(masm, 1983b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch use_sse3_, 1984b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ¬_floats); 1985b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 19863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch case Token::BIT_OR: __ or_(eax, ecx); break; 19873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch case Token::BIT_AND: __ and_(eax, ecx); break; 19883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch case Token::BIT_XOR: __ xor_(eax, ecx); break; 1989b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: __ sar_cl(eax); break; 1990b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: __ shl_cl(eax); break; 1991b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: __ shr_cl(eax); break; 1992b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 1993b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1994b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ == Token::SHR) { 1995b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result is non-negative and fits in a smi. 1996b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(eax, Immediate(0xc0000000)); 1997b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &call_runtime); 1998b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 1999b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result fits in a smi. 2000b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(eax, 0xc0000000); 200169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(negative, &non_smi_result, Label::kNear); 2002b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2003b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag smi result and return. 2004b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(eax); 2005b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 2006b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2007b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // All ops except SHR return a signed int32 that we load in 2008b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // a HeapNumber. 2009b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ != Token::SHR) { 2010b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&non_smi_result); 2011b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number if needed. 20123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, eax); // ebx: result 2013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label skip_allocation; 2014b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode_) { 2015b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: 2016b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: 2017b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the operand was an object, we skip the 2018b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 2019b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 2020b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1 * kPointerSize : 2 * kPointerSize)); 20213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 2022b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fall through! 2023b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: 2024b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 2025b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 2026b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2027b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 2028b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2029b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Store the result in the HeapNumber and return. 20308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 2031b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 20323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(xmm0, ebx); 2033b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 2034b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 2035b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ebx); 2036b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fild_s(Operand(esp, 1 * kPointerSize)); 2037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2039b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 2040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2042b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 2043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateTypeTransitionWithSavedArgs(masm); 2044b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); break; 2047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If an allocation fails, or SHR or MOD hit a hard case, 2050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // use the runtime system to get the correct result. 2051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&call_runtime); 2052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2053b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 2054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 2055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 2056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 2057b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2058b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 2059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 2060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 2061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 2063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 2064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 2065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 2067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 2068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 2069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 2071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 2072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 2073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 2075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 2076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2077b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 2078b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 2079b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2080b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 2081b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 2082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 2084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 2085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2086b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 2087b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 2088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 2090b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 2091b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 2093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 2094b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2095b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2096b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2097b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2098257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { 2099b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label call_runtime; 2100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 210144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 210244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->generic_binary_stub_calls(), 1); 2103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2104b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 2105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 2106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 2107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 2108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 2109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 2111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 2112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 2113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 2114b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 2115b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 2116b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 2117b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 2118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 2120b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 2121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 2124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Floating point case. 2126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 2127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: 2128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 2129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 2130b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: { 2131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label not_floats; 21328b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 2133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 2134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 2135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2136b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 2137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ addsd(xmm0, xmm1); break; 2138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ subsd(xmm0, xmm1); break; 2139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ mulsd(xmm0, xmm1); break; 2140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ divsd(xmm0, xmm1); break; 2141b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 2142b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2143b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &call_runtime); 2144b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 2145b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 2146b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // SSE2 not available, use FPU. 2147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); 2148b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadFloatOperands( 2149b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch masm, 2150b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ecx, 2151b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::ARGS_IN_REGISTERS); 2152b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 2153b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: __ faddp(1); break; 2154b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: __ fsubp(1); break; 2155b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: __ fmulp(1); break; 2156b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: __ fdivp(1); break; 2157b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 2158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2159b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label after_alloc_failure; 2160b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateHeapResultAllocation(masm, &after_alloc_failure); 2161b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2162b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 2163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&after_alloc_failure); 2164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ffree(); 2165b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&call_runtime); 2166b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2167b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_floats); 2168b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2169b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2170b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: { 2171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // For MOD we go directly to runtime in the non-smi case. 2172b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2174b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 2175b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 2176b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 2177b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 2178b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 2179b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: { 2180b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label non_smi_result; 2181b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch FloatingPointHelper::LoadUnknownsAsIntegers(masm, 2182b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch use_sse3_, 2183b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch &call_runtime); 2184b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 21853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch case Token::BIT_OR: __ or_(eax, ecx); break; 21863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch case Token::BIT_AND: __ and_(eax, ecx); break; 21873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch case Token::BIT_XOR: __ xor_(eax, ecx); break; 2188b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: __ sar_cl(eax); break; 2189b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: __ shl_cl(eax); break; 2190b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: __ shr_cl(eax); break; 2191b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 2192b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2193b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ == Token::SHR) { 2194b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result is non-negative and fits in a smi. 2195b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ test(eax, Immediate(0xc0000000)); 2196b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, &call_runtime); 2197b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 2198b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if result fits in a smi. 2199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(eax, 0xc0000000); 220069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(negative, &non_smi_result, Label::kNear); 2201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2202b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Tag smi result and return. 2203b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiTag(eax); 2204b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); // Drop the arguments from the stack. 2205b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // All ops except SHR return a signed int32 that we load in 2207b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // a HeapNumber. 2208b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (op_ != Token::SHR) { 2209b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&non_smi_result); 2210b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number if needed. 22113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, eax); // ebx: result 2212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label skip_allocation; 2213b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode_) { 2214b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: 2215b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: 2216b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the operand was an object, we skip the 2217b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 2218b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 2219b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1 * kPointerSize : 2 * kPointerSize)); 22203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 2221b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fall through! 2222b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: 2223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 2224b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 2225b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2226b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 2227b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2228b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Store the result in the HeapNumber and return. 22298b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 2230b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 22313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(xmm0, ebx); 2232b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 2233b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 2234b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ebx); 2235b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fild_s(Operand(esp, 1 * kPointerSize)); 2236b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2237b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2238b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(2 * kPointerSize); 2239b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2240b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2241b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2242b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); break; 2243b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2244b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2245b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If all else fails, use the runtime system to get the correct 2246b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // result. 2247b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&call_runtime); 2248b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (op_) { 2249b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::ADD: { 22501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateAddStrings(masm); 2251b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 2252b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 2253b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2254b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2255b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SUB: 2256b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 2257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 2258b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2259b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MUL: 2260b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 2261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 2262b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::DIV: 2264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateRegisterArgsPush(masm); 2265b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 2266b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2267b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::MOD: 2268b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 2269b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2270b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_OR: 2271b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 2272b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2273b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_AND: 2274b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 2275b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2276b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::BIT_XOR: 2277b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 2278b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2279b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SAR: 2280b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 2281b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2282b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHL: 2283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 2284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case Token::SHR: 2286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 2287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: 2289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNREACHABLE(); 2290b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2291b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2292b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2293b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2294257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { 2295e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ASSERT(op_ == Token::ADD); 2296257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label left_not_string, call_runtime; 22971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 22981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Registers containing left and right operands respectively. 22991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register left = edx; 23001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register right = eax; 23011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 23021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Test if left operand is a string. 23033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(left, &left_not_string, Label::kNear); 23041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); 2305257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &left_not_string, Label::kNear); 23061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 23071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); 23081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateRegisterArgsPush(masm); 23091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ TailCallStub(&string_add_left_stub); 23101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 23111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Left operand is not a string, test right. 23121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&left_not_string); 23133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(right, &call_runtime, Label::kNear); 23141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); 2315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &call_runtime, Label::kNear); 23161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 23171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); 23181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateRegisterArgsPush(masm); 23191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ TailCallStub(&string_add_right_stub); 23201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 23211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Neither argument is a string. 23221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&call_runtime); 23231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 23241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 23251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapResultAllocation( 2327b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch MacroAssembler* masm, 2328b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* alloc_failure) { 2329b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label skip_allocation; 2330b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch OverwriteMode mode = mode_; 2331b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch switch (mode) { 2332b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_LEFT: { 2333b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the argument in edx is already an object, we skip the 2334b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 23353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(edx, &skip_allocation, Label::kNear); 2336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number for the result. Keep eax and edx intact 2337b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // for the possible runtime call. 2338b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); 2339b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Now edx can be overwritten losing one of the arguments as we are 2340b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // now done and will not need it any more. 23413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edx, ebx); 2342b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 2343b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Use object in edx as a result holder 23443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(eax, edx); 2345b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2346b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2347b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case OVERWRITE_RIGHT: 2348b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If the argument in eax is already an object, we skip the 2349b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // allocation of a heap number. 23503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 2351b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fall through! 2352b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case NO_OVERWRITE: 2353b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate a heap number for the result. Keep eax and edx intact 2354b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // for the possible runtime call. 2355b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); 2356b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Now eax can be overwritten losing one of the arguments as we are 2357b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // now done and will not need it any more. 2358b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, ebx); 2359b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_allocation); 2360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch break; 2361b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch default: UNREACHABLE(); 2362b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2363b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2364b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2365b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { 236780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ecx); 2368b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(edx); 2369b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(eax); 237080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ecx); 237180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 237280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 237380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 237480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::Generate(MacroAssembler* masm) { 2375b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // TAGGED case: 2376b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input: 2377b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // esp[4]: tagged number input argument (should be number). 2378b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // esp[0]: return address. 2379b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Output: 2380b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax: tagged double result. 2381b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // UNTAGGED case: 2382b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input:: 2383b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // esp[0]: return address. 2384b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // xmm1: untagged double input argument 2385b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Output: 2386b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // xmm1: untagged double result. 2387b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 238880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime_call; 238980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime_call_clear_stack; 2390b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label skip_cache; 2391b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const bool tagged = (argument_type_ == TAGGED); 2392b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2393b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Test that eax is a number. 2394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label input_not_smi; 2395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loaded; 2396b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, Operand(esp, kPointerSize)); 23973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &input_not_smi, Label::kNear); 2398b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input is a smi. Untag and load it onto the FPU stack. 2399b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Then load the low and high words of the double into ebx, edx. 2400b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTagSize == 1); 2401b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sar(eax, 1); 24023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(esp, Immediate(2 * kPointerSize)); 2403b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(esp, 0), eax); 2404b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fild_s(Operand(esp, 0)); 2405b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fst_d(Operand(esp, 0)); 2406b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(edx); 2407b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pop(ebx); 2408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&loaded, Label::kNear); 2409b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&input_not_smi); 2410b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check if input is a HeapNumber. 2411b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 241244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 24133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ebx, Immediate(factory->heap_number_map())); 2414b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_equal, &runtime_call); 2415b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input is a HeapNumber. Push it on the FPU stack and load its 2416b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // low and high words into ebx, edx. 2417b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2418b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); 2419b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset)); 2420b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2421b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&loaded); 2422b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 24238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE4_1)) { 2424b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope sse4_scope(SSE4_1); 24253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pextrd(edx, xmm1, 0x1); // copy xmm1[63..32] to edx. 2426b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 2427b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ pshufd(xmm0, xmm1, 0x1); 24283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movd(edx, xmm0); 2429b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 24303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movd(ebx, xmm1); 2431b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 243280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2433b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ST[0] or xmm1 == double value 243480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx = low 32 bits of double value 243580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx = high 32 bits of double value 243680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compute hash (the shifts are arithmetic): 243780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); 243880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, ebx); 24393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(ecx, edx); 244080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, ecx); 244180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sar(eax, 16); 24423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(ecx, eax); 244380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, ecx); 244480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sar(eax, 8); 24453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(ecx, eax); 244644f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize)); 24473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(ecx, 244844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(TranscendentalCache::SubCache::kCacheSize - 1)); 244980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2450b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ST[0] or xmm1 == double value. 245180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx = low 32 bits of double value. 245280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx = high 32 bits of double value. 245380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx = TranscendentalCache::hash(double value). 245444f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference cache_array = 245544f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::transcendental_cache_array_address(masm->isolate()); 245644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, Immediate(cache_array)); 245744f0eee88ff00398ff7f715fab053374d808c90dSteve Block int cache_array_index = 245844f0eee88ff00398ff7f715fab053374d808c90dSteve Block type_ * sizeof(masm->isolate()->transcendental_cache()->caches_[0]); 245944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, Operand(eax, cache_array_index)); 246080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Eax points to the cache for the type type_. 246180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If NULL, the cache hasn't been initialized yet, so go through runtime. 24623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(eax, eax); 246380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &runtime_call_clear_stack); 246480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG 246580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the layout of cache elements match expectations. 246644f0eee88ff00398ff7f715fab053374d808c90dSteve Block { TranscendentalCache::SubCache::Element test_elem[2]; 246780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_start = reinterpret_cast<char*>(&test_elem[0]); 246880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); 246980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); 247080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); 247180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); 247280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. 247380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(0, elem_in0 - elem_start); 247480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(kIntSize, elem_in1 - elem_start); 247580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(2 * kIntSize, elem_out - elem_start); 247680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 247780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 247880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find the address of the ecx'th entry in the cache, i.e., &eax[ecx*12]. 247980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(ecx, ecx, times_2, 0)); 248080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(eax, ecx, times_4, 0)); 248180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if cache matches: Double value is stored in uint32_t[2] array. 2482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label cache_miss; 248380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(ebx, Operand(ecx, 0)); 2484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &cache_miss, Label::kNear); 248580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, Operand(ecx, kIntSize)); 2486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &cache_miss, Label::kNear); 248780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Cache hit! 24883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Counters* counters = masm->isolate()->counters(); 24893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ IncrementCounter(counters->transcendental_cache_hit(), 1); 249080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(ecx, 2 * kIntSize)); 2491b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2492b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp(0); 2493b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(kPointerSize); 2494b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 2495b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2496b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 2497b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 249880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 249980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&cache_miss); 25003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ IncrementCounter(counters->transcendental_cache_miss(), 1); 250180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Update cache with new value. 250280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We are short on registers, so use no_reg as scratch. 250380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // This gives slightly larger code. 2504b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2505b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack); 2506b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 2507b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); 25083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(esp, Immediate(kDoubleSize)); 2509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(Operand(esp, 0), xmm1); 2510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fld_d(Operand(esp, 0)); 25113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(esp, Immediate(kDoubleSize)); 2512b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 25133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateOperation(masm, type_); 251480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(ecx, 0), ebx); 251580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(ecx, kIntSize), edx); 251680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(ecx, 2 * kIntSize), eax); 251780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2518b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2519b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(kPointerSize); 2520b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 2521b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2522b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 2523b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2524b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Skip cache and return answer directly, only in untagged case. 2525b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&skip_cache); 25263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(esp, Immediate(kDoubleSize)); 2527b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(Operand(esp, 0), xmm1); 2528b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fld_d(Operand(esp, 0)); 25293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateOperation(masm, type_); 2530b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp_d(Operand(esp, 0)); 2531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, Operand(esp, 0)); 25323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(esp, Immediate(kDoubleSize)); 2533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // We return the value in xmm1 without adding it to the cache, but 2534b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // we cause a scavenging GC so that future allocations will succeed. 25353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 25363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FrameScope scope(masm, StackFrame::INTERNAL); 25373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Allocate an unused object bigger than a HeapNumber. 25383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(Immediate(Smi::FromInt(2 * kDoubleSize))); 25393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); 25403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 2542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 254380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Call runtime, doing whatever allocation and cleanup is necessary. 2545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (tagged) { 2546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&runtime_call_clear_stack); 2547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp(0); 2548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&runtime_call); 254944f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference runtime = 255044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference(RuntimeFunction(), masm->isolate()); 255144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ TailCallExternalReference(runtime, 1, 1); 2552b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { // UNTAGGED. 2553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&runtime_call_clear_stack); 2554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&runtime_call); 2555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); 2556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm1); 25573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 25583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FrameScope scope(masm, StackFrame::INTERNAL); 25593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(eax); 25603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallRuntime(RuntimeFunction(), 1); 25613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 2564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 256580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 256680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 256780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 256880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian MonsenRuntime::FunctionId TranscendentalCacheStub::RuntimeFunction() { 256980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen switch (type_) { 257080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case TranscendentalCache::SIN: return Runtime::kMath_sin; 257180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case TranscendentalCache::COS: return Runtime::kMath_cos; 25723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch case TranscendentalCache::TAN: return Runtime::kMath_tan; 2573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case TranscendentalCache::LOG: return Runtime::kMath_log; 257480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen default: 257580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen UNIMPLEMENTED(); 257680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return Runtime::kAbort; 257780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 257880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 257980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 258080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 25813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid TranscendentalCacheStub::GenerateOperation( 25823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler* masm, TranscendentalCache::Type type) { 258380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Only free register is edi. 2584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input value is on FP stack, and also in ebx/edx. 2585b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input value is possibly in xmm1. 2586b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Address of result (a newly allocated HeapNumber) may be in eax. 25873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (type == TranscendentalCache::SIN || 25883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch type == TranscendentalCache::COS || 25893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch type == TranscendentalCache::TAN) { 2590b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Both fsin and fcos require arguments in the range +/-2^63 and 2591b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // return NaN for infinities and NaN. They can share all code except 2592b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // the actual fsin/fcos operation. 2593257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label in_range, done; 2594b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If argument is outside the range -2^63..2^63, fsin/cos doesn't 2595b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // work. We must reduce it to the appropriate range. 2596b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edi, edx); 25973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(edi, Immediate(0x7ff00000)); // Exponent only. 2598b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch int supported_exponent_limit = 2599b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift; 26003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(edi, Immediate(supported_exponent_limit)); 2601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, &in_range, Label::kNear); 2602b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check for infinity and NaN. Both return NaN for sin. 26033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(edi, Immediate(0x7ff00000)); 2604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_nan_result; 2605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &non_nan_result, Label::kNear); 2606b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Input is +/-Infinity or NaN. Result is NaN. 2607b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fstp(0); 2608b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // NaN is represented by 0x7ff8000000000000. 2609b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(0x7ff80000)); 2610b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ push(Immediate(0)); 2611b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ fld_d(Operand(esp, 0)); 26123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(esp, Immediate(2 * kPointerSize)); 2613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 261480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_nan_result); 261680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Use fpmod to restrict argument to the range +/-2*PI. 2618257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(edi, eax); // Save eax before using fnstsw_ax. 2619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fldpi(); 2620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fadd(0); 2621257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fld(1); 2622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // FPU Stack: input, 2*pi, input. 2623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch { 2624257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label no_exceptions; 2625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fwait(); 2626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fnstsw_ax(); 2627257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Clear if Illegal Operand or Zero Division exceptions are set. 26283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(eax, Immediate(5)); 2629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &no_exceptions, Label::kNear); 2630257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fnclex(); 2631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&no_exceptions); 2632257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 263380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute st(0) % st(1) 2635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch { 2636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label partial_remainder_loop; 2637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&partial_remainder_loop); 2638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fprem1(); 2639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fwait(); 2640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fnstsw_ax(); 26413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(eax, Immediate(0x400 /* C2 */)); 2642257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If C2 is set, computation only has partial result. Loop to 2643257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // continue computation. 2644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &partial_remainder_loop); 2645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 2646257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // FPU Stack: input, 2*pi, input % 2*pi 2647257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fstp(2); 2648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fstp(0); 2649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(eax, edi); // Restore eax (allocated HeapNumber pointer). 265080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2651257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // FPU Stack: input % 2*pi 2652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&in_range); 26533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch switch (type) { 2654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case TranscendentalCache::SIN: 2655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fsin(); 2656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 2657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case TranscendentalCache::COS: 2658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fcos(); 2659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 26603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch case TranscendentalCache::TAN: 26613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // FPTAN calculates tangent onto st(0) and pushes 1.0 onto the 26623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // FP register stack. 26633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fptan(); 26643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fstp(0); // Pop FP register stack. 26653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch break; 2666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 2667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 266880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 2669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&done); 2670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 26713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(type == TranscendentalCache::LOG); 2672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fldln2(); 2673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fxch(); 2674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ fyl2x(); 267580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 267680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 267780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 267880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 267980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Input: edx, eax are the left and right objects of a bit op. 268080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Output: eax, ecx are left and right integers for a bit op. 268180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm, 268280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool use_sse3, 268380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* conversion_failure) { 268480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check float operands. 268580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label arg1_is_object, check_undefined_arg1; 268680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label arg2_is_object, check_undefined_arg2; 268780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label load_arg2, done; 268880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 268980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Test if arg1 is a Smi. 269069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfNotSmi(edx, &arg1_is_object, Label::kNear); 269180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 269280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edx); 269380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_arg2); 269480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 269580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the argument is undefined it converts to zero (ECMA-262, section 9.5). 269680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_undefined_arg1); 269744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 269844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(edx, factory->undefined_value()); 269980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, conversion_failure); 270080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Immediate(0)); 270180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_arg2); 270280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 270380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&arg1_is_object); 270480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 270544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(ebx, factory->heap_number_map()); 270680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &check_undefined_arg1); 270780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 270880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the untagged integer version of the edx heap number in ecx. 2709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch IntegerConvert(masm, edx, use_sse3, conversion_failure); 271080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, ecx); 271180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 271280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Here edx has the untagged integer, eax has a Smi or a heap number. 271380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_arg2); 271480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 271580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Test if arg2 is a Smi. 271669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfNotSmi(eax, &arg2_is_object, Label::kNear); 271780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 271880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(eax); 271980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, eax); 272080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&done); 272180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 272280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the argument is undefined it converts to zero (ECMA-262, section 9.5). 272380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_undefined_arg2); 272444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, factory->undefined_value()); 272580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, conversion_failure); 272680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(0)); 272780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&done); 272880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 272980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&arg2_is_object); 273080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 273144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(ebx, factory->heap_number_map()); 273280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &check_undefined_arg2); 273380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 273480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the untagged integer version of the eax heap number in ecx. 2735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch IntegerConvert(masm, eax, use_sse3, conversion_failure); 273680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 273780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, edx); 273880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 273980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 274080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckLoadedIntegersWereInt32(MacroAssembler* masm, 2742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch bool use_sse3, 2743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* not_int32) { 2744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return; 2745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 274880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, 274980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register number) { 2750257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_smi, done; 275180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 27523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(number, &load_smi, Label::kNear); 275380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); 2754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 275580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 275680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi); 275780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(number); 275880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(number); 275980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 276080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(number); 276180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 276280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 276380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 276480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 276580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 276680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm) { 2767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_smi_edx, load_eax, load_smi_eax, done; 276880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in edx into xmm0. 27693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); 277080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 277180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 277280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_eax); 277380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in eax into xmm1. 27743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); 277580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 277780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 277880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_edx); 277980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edx); // Untag smi before converting to float. 27803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(xmm0, edx); 278180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(edx); // Retag smi for heap number overwriting test. 278280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_eax); 278380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 278480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_eax); 278580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(eax); // Untag smi before converting to float. 27863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(xmm1, eax); 278780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(eax); // Retag smi for heap number overwriting test. 278880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 278980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 279080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 279180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 279280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 279380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm, 279480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_numbers) { 2795257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; 279680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in edx into xmm0, or branch to not_numbers. 27973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); 279844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 279944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map()); 280080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_numbers); // Argument in edx is not a number. 280180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 280280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_eax); 280380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load operand in eax into xmm1, or branch to not_numbers. 28043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); 280544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map()); 2806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &load_float_eax, Label::kNear); 280780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(not_numbers); // Argument in eax is not a number. 280880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_edx); 280980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edx); // Untag smi before converting to float. 28103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(xmm0, edx); 281180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(edx); // Retag smi for heap number overwriting test. 281280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&load_eax); 281380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_eax); 281480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(eax); // Untag smi before converting to float. 28153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(xmm1, eax); 281680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(eax); // Retag smi for heap number overwriting test. 2817257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 281880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_float_eax); 281980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 282080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 282180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 282280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 282380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 282480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Smis(MacroAssembler* masm, 282580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 282680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const Register left = edx; 282780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const Register right = eax; 282880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, left); 282980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(right)); // We're about to clobber scratch. 283080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 28313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(xmm0, scratch); 283280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 283380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, right); 283480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 28353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(xmm1, scratch); 283680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 283780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 283880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2839b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm, 2840b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* non_int32, 2841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register scratch) { 2842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvttsd2si(scratch, Operand(xmm0)); 28433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(xmm2, scratch); 2844b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm0, xmm2); 2845b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, non_int32); 2846b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(carry, non_int32); 2847b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cvttsd2si(scratch, Operand(xmm1)); 28483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(xmm2, scratch); 2849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm1, xmm2); 2850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_zero, non_int32); 2851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(carry, non_int32); 2852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 285580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, 285680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch, 285780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ArgLocation arg_location) { 2858257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_smi_1, load_smi_2, done_load_1, done; 285980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (arg_location == ARGS_IN_REGISTERS) { 286080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, edx); 286180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 286280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, Operand(esp, 2 * kPointerSize)); 286380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 28643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(scratch, &load_smi_1, Label::kNear); 286580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); 286680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done_load_1); 286780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 286880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (arg_location == ARGS_IN_REGISTERS) { 286980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, eax); 287080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 287180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, Operand(esp, 1 * kPointerSize)); 287280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 28733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(scratch, &load_smi_2, Label::kNear); 287480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); 2875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 287680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 287780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_1); 287880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 287980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(scratch); 288080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 288180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(scratch); 288280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&done_load_1); 288380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 288480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_smi_2); 288580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 288680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(scratch); 288780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 288880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(scratch); 288980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 289080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 289180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 289280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 289380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 289480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatSmis(MacroAssembler* masm, 289580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 289680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const Register left = edx; 289780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const Register right = eax; 289880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, left); 289980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(right)); // We're about to clobber scratch. 290080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 290180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(scratch); 290280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 290380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 290480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, right); 290580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 290680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 0), scratch); 290780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fild_s(Operand(esp, 0)); 290880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(scratch); 290980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 291080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 291180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 291280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, 291380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* non_float, 291480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 2915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label test_other, done; 291680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Test if both operands are floats or smi -> scratch=k_is_float; 291780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Otherwise scratch = k_not_float. 29183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(edx, &test_other, Label::kNear); 291980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset)); 292044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 292144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(scratch, factory->heap_number_map()); 292280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, non_float); // argument in edx is not a number -> NaN 292380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 292480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&test_other); 29253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &done, Label::kNear); 292680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset)); 292744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(scratch, factory->heap_number_map()); 292880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, non_float); // argument in eax is not a number -> NaN 292980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 293080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fall-through: Both operands are numbers. 293180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 293280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 293380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 293480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 2935b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm, 2936b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label* non_int32) { 2937b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return; 2938b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2939b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2940b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2941b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid MathPowStub::Generate(MacroAssembler* masm) { 2942b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope use_sse2(SSE2); 294344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 29443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const Register exponent = eax; 29453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const Register base = edx; 29463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const Register scratch = ecx; 29473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const XMMRegister double_result = xmm3; 29483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const XMMRegister double_base = xmm2; 29493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const XMMRegister double_exponent = xmm1; 29503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const XMMRegister double_scratch = xmm4; 29513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 29523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label call_runtime, done, exponent_not_smi, int_exponent; 29533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 29543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Save 1 in double_result - we need this several times later on. 29553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(scratch, Immediate(1)); 29563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(double_result, scratch); 29573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 29583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (exponent_type_ == ON_STACK) { 29593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label base_is_smi, unpack_exponent; 29603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // The exponent and base are supplied as arguments on the stack. 29613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // This can only happen if the stub is called from non-optimized code. 29623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load input parameters from stack. 29633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(base, Operand(esp, 2 * kPointerSize)); 29643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(exponent, Operand(esp, 1 * kPointerSize)); 29653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 29663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfSmi(base, &base_is_smi, Label::kNear); 29673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(FieldOperand(base, HeapObject::kMapOffset), 29683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch factory->heap_number_map()); 29693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &call_runtime); 29703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 29713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movdbl(double_base, FieldOperand(base, HeapNumber::kValueOffset)); 29723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&unpack_exponent, Label::kNear); 29733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 29743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&base_is_smi); 29753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ SmiUntag(base); 29763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(double_base, base); 29773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 29783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&unpack_exponent); 29793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear); 29803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ SmiUntag(exponent); 29813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&int_exponent); 29823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 29833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&exponent_not_smi); 29843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(FieldOperand(exponent, HeapObject::kMapOffset), 29853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch factory->heap_number_map()); 29863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &call_runtime); 29873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movdbl(double_exponent, 29883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FieldOperand(exponent, HeapNumber::kValueOffset)); 29893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else if (exponent_type_ == TAGGED) { 29903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear); 29913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ SmiUntag(exponent); 29923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&int_exponent); 29933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 29943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&exponent_not_smi); 29953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movdbl(double_exponent, 29963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FieldOperand(exponent, HeapNumber::kValueOffset)); 29973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2998b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 29993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (exponent_type_ != INTEGER) { 30003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label fast_power; 30013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Detect integer exponents stored as double. 30023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvttsd2si(exponent, Operand(double_exponent)); 30033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Skip to runtime if possibly NaN (indicated by the indefinite integer). 30043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(exponent, Immediate(0x80000000u)); 30053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(equal, &call_runtime); 30063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(double_scratch, exponent); 30073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Already ruled out NaNs for exponent. 30083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ucomisd(double_exponent, double_scratch); 30093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(equal, &int_exponent); 30103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 30113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (exponent_type_ == ON_STACK) { 30123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Detect square root case. Crankshaft detects constant +/-0.5 at 30133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // compile time and uses DoMathPowHalf instead. We then skip this check 30143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // for non-constant cases of +/-0.5 as these hardly occur. 30153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label continue_sqrt, continue_rsqrt, not_plus_half; 30163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Test for 0.5. 30173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load double_scratch with 0.5. 30183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(scratch, Immediate(0x3F000000u)); 30193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movd(double_scratch, scratch); 30203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtss2sd(double_scratch, double_scratch); 30213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Already ruled out NaNs for exponent. 30223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ucomisd(double_scratch, double_exponent); 30233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, ¬_plus_half, Label::kNear); 30243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 30253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Calculates square root of base. Check for the special case of 30263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13). 30273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // According to IEEE-754, single-precision -Infinity has the highest 30283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // 9 bits set and the lowest 23 bits cleared. 30293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(scratch, 0xFF800000u); 30303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movd(double_scratch, scratch); 30313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtss2sd(double_scratch, double_scratch); 30323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ucomisd(double_base, double_scratch); 30333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Comparing -Infinity with NaN results in "unordered", which sets the 30343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // zero flag as if both were equal. However, it also sets the carry flag. 30353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &continue_sqrt, Label::kNear); 30363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(carry, &continue_sqrt, Label::kNear); 30373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 30383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set result to Infinity in the special case. 30393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xorps(double_result, double_result); 30403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ subsd(double_result, double_scratch); 30413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&done); 30423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 30433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&continue_sqrt); 30443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // sqrtsd returns -0 when input is -0. ECMA spec requires +0. 30453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xorps(double_scratch, double_scratch); 30463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ addsd(double_scratch, double_base); // Convert -0 to +0. 30473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sqrtsd(double_result, double_scratch); 30483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&done); 30493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 30503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Test for -0.5. 30513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(¬_plus_half); 30523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load double_exponent with -0.5 by substracting 1. 30533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ subsd(double_scratch, double_result); 30543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Already ruled out NaNs for exponent. 30553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ucomisd(double_scratch, double_exponent); 30563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &fast_power, Label::kNear); 30573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 30583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Calculates reciprocal of square root of base. Check for the special 30593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13). 30603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // According to IEEE-754, single-precision -Infinity has the highest 30613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // 9 bits set and the lowest 23 bits cleared. 30623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(scratch, 0xFF800000u); 30633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movd(double_scratch, scratch); 30643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtss2sd(double_scratch, double_scratch); 30653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ucomisd(double_base, double_scratch); 30663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Comparing -Infinity with NaN results in "unordered", which sets the 30673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // zero flag as if both were equal. However, it also sets the carry flag. 30683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &continue_rsqrt, Label::kNear); 30693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(carry, &continue_rsqrt, Label::kNear); 30703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 30713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set result to 0 in the special case. 30723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xorps(double_result, double_result); 30733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&done); 30743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 30753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&continue_rsqrt); 30763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // sqrtsd returns -0 when input is -0. ECMA spec requires +0. 30773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xorps(double_exponent, double_exponent); 30783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ addsd(double_exponent, double_base); // Convert -0 to +0. 30793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sqrtsd(double_exponent, double_exponent); 30803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ divsd(double_result, double_exponent); 30813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&done); 30823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 3083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 30843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Using FPU instructions to calculate power. 30853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label fast_power_failed; 30863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&fast_power); 30873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fnclex(); // Clear flags to catch exceptions later. 30883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Transfer (B)ase and (E)xponent onto the FPU register stack. 30893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(esp, Immediate(kDoubleSize)); 30903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movdbl(Operand(esp, 0), double_exponent); 30913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fld_d(Operand(esp, 0)); // E 30923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movdbl(Operand(esp, 0), double_base); 30933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fld_d(Operand(esp, 0)); // B, E 30943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 30953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Exponent is in st(1) and base is in st(0) 30963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B) 30973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // FYL2X calculates st(1) * log2(st(0)) 30983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fyl2x(); // X 30993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fld(0); // X, X 31003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ frndint(); // rnd(X), X 31013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fsub(1); // rnd(X), X-rnd(X) 31023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fxch(1); // X - rnd(X), rnd(X) 31033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1 31043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X) 31053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X) 31063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ faddp(1); // 1, 2^(X-rnd(X)), rnd(X) 31073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // FSCALE calculates st(0) * 2^st(1) 31083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fscale(); // 2^X, rnd(X) 31093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fstp(1); 31103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Bail out to runtime in case of exceptions in the status word. 31113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fnstsw_ax(); 31123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test_b(eax, 0x5F); // We check for all but precision exception. 31133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_zero, &fast_power_failed, Label::kNear); 31143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fstp_d(Operand(esp, 0)); 31153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movdbl(double_result, Operand(esp, 0)); 31163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(esp, Immediate(kDoubleSize)); 31173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&done); 31183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 31193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&fast_power_failed); 31203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fninit(); 31213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(esp, Immediate(kDoubleSize)); 31223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&call_runtime); 31233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 3124c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch 31253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Calculate power with integer exponent. 31263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&int_exponent); 31273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const XMMRegister double_scratch2 = double_exponent; 31283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(scratch, exponent); // Back up exponent. 31293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movsd(double_scratch, double_base); // Back up base. 31303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movsd(double_scratch2, double_result); // Load double_exponent with 1. 3131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Get absolute value of exponent. 31333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label no_neg, while_true, no_multiply; 31343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(scratch, scratch); 31353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(positive, &no_neg, Label::kNear); 31363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ neg(scratch); 3137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&no_neg); 3138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&while_true); 31403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ shr(scratch, 1); 3141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_carry, &no_multiply, Label::kNear); 31423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mulsd(double_result, double_scratch); 3143b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&no_multiply); 3144b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 31453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mulsd(double_scratch, double_scratch); 31463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_zero, &while_true); 3147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 31483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // scratch has the original value of the exponent - if the exponent is 31493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // negative, return 1/result. 31503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(exponent, exponent); 31513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(positive, &done); 31523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ divsd(double_scratch2, double_result); 31533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movsd(double_result, double_scratch2); 31543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Test whether result is zero. Bail out to check for subnormal result. 31553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. 31563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xorps(double_scratch2, double_scratch2); 31573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ucomisd(double_scratch2, double_result); // Result cannot be NaN. 31583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // double_exponent aliased as double_scratch2 has already been overwritten 31593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // and may not have contained the exponent value in the first place when the 31603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // exponent is a smi. We reset it with exponent value before bailing out. 31613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &done); 31623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cvtsi2sd(double_exponent, exponent); 31633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 31643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Returning or bailing out. 31653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Counters* counters = masm->isolate()->counters(); 31663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (exponent_type_ == ON_STACK) { 31673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // The arguments are still on the stack. 31683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&call_runtime); 31693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); 3170b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 31713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // The stub is called from non-optimized code, which expects the result 31723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // as heap number in exponent. 31733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&done); 31743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateHeapNumber(eax, scratch, base, &call_runtime); 31753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), double_result); 31763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ IncrementCounter(counters->math_pow(), 1); 31773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(2 * kPointerSize); 31783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 31793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&call_runtime); 31803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 31813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch AllowExternalCallThatCantCauseGC scope(masm); 31823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ PrepareCallCFunction(4, scratch); 31833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movdbl(Operand(esp, 0 * kDoubleSize), double_base); 31843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movdbl(Operand(esp, 1 * kDoubleSize), double_exponent); 31853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallCFunction( 31863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference::power_double_double_function(masm->isolate()), 4); 31873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 31883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Return value is in st(0) on ia32. 31893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Store it into the (fixed) result register. 31903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(esp, Immediate(kDoubleSize)); 31913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ fstp_d(Operand(esp, 0)); 31923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movdbl(double_result, Operand(esp, 0)); 31933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(esp, Immediate(kDoubleSize)); 319485b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch 31953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&done); 31963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ IncrementCounter(counters->math_pow(), 1); 31973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(0); 31983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 3199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 3200b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 320280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { 320380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The key is in edx and the parameter count is in eax. 320480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 320580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The displacement is used for skipping the frame pointer on the 320680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stack. It is the offset of the last parameter (if any) relative 320780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // to the frame pointer. 320880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kDisplacement = 1 * kPointerSize; 320980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 321080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the key is a smi. 321180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow; 321269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfNotSmi(edx, &slow, Label::kNear); 321380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 321480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the calling frame is an arguments adaptor frame. 3215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label adaptor; 321680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 321780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset)); 32183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 3219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &adaptor, Label::kNear); 322080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 322180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check index against formal parameters count limit passed in 322280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // through register eax. Use unsigned comparison to get negative 322380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // check for free. 32243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(edx, eax); 322569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(above_equal, &slow, Label::kNear); 322680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 322780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the argument from the stack and return it. 322880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize == 1); 322980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these. 323080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ebx, Operand(ebp, eax, times_2, 0)); 323180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ neg(edx); 323280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); 323380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 323480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 323580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Arguments adaptor case: Check index against actual arguments 323680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // limit found in the arguments adaptor frame. Use unsigned 323780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // comparison to get negative check for free. 323880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&adaptor); 323980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 32403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(edx, ecx); 324169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(above_equal, &slow, Label::kNear); 324280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 324380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the argument from the stack and return it. 324480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize == 1); 324580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these. 324680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ebx, Operand(ebx, ecx, times_2, 0)); 324780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ neg(edx); 324880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); 324980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 325080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 325180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case: Handle non-smi or out-of-bounds access to arguments 325280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // by calling the runtime system. 325380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 325480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ebx); // Return address. 325580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(edx); 325680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ebx); 325780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); 325880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 325980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 326080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 32613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { 326280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[0] : return address 326380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[4] : number of parameters 326480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[8] : receiver displacement 32653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] : function 32663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 32673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Check if the calling frame is an arguments adaptor frame. 32683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label runtime; 32693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 32703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 32713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 32723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(not_equal, &runtime, Label::kNear); 32733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 32743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Patch the arguments.length and the parameters pointer. 32753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 32763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ecx); 32773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edx, Operand(edx, ecx, times_2, 32783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch StandardFrameConstants::kCallerSPOffset)); 32793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(Operand(esp, 2 * kPointerSize), edx); 32803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 32813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&runtime); 32823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); 32833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch} 32843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 32853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 32863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { 32873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] : return address 32883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] : number of parameters (tagged) 32893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] : receiver displacement 32903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] : function 32913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 32923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = parameter count (tagged) 32933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, Operand(esp, 1 * kPointerSize)); 32943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 32953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Check if the calling frame is an arguments adaptor frame. 32963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // TODO(rossberg): Factor out some of the bits that are shared with the other 32973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Generate* functions. 32983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label runtime; 32993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label adaptor_frame, try_allocate; 33003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 33013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 33023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 33033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(equal, &adaptor_frame, Label::kNear); 33043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // No adaptor, parameter count = argument count. 33063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, ebx); 33073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(&try_allocate, Label::kNear); 33083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We have an adaptor frame. Patch the parameters pointer. 33103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&adaptor_frame); 33113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 33123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edx, Operand(edx, ecx, times_2, 33133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch StandardFrameConstants::kCallerSPOffset)); 33143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(Operand(esp, 2 * kPointerSize), edx); 33153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = parameter count (tagged) 33173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 33183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] = parameter count (tagged) 33193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = address of receiver argument 33203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Compute the mapped parameter count = min(ebx, ecx) in ebx. 33213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ebx, ecx); 33223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(less_equal, &try_allocate, Label::kNear); 33233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, ecx); 33243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&try_allocate); 33263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Save mapped parameter count. 33283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(ebx); 33293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Compute the sizes of backing store, parameter map, and arguments object. 33313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 1. Parameter map, has 2 extra words containing context and backing store. 33323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int kParameterMapHeaderSize = 33333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch FixedArray::kHeaderSize + 2 * kPointerSize; 33343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label no_parameter_map; 33353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(ebx, ebx); 33363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(zero, &no_parameter_map, Label::kNear); 33373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize)); 33383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&no_parameter_map); 33393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 2. Backing store. 33413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); 33423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 3. Arguments object. 33443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(ebx, Immediate(Heap::kArgumentsObjectSize)); 33453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Do the allocation of all three objects in one go. 33473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT); 33483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // eax = address of new object(s) (tagged) 33503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 33513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = mapped parameter count (tagged) 33523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = parameter count (tagged) 33533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] = address of receiver argument 33543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Get the arguments boilerplate from the current (global) context into edi. 33553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label has_mapped_parameters, copy; 33563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 33573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); 33583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, Operand(esp, 0 * kPointerSize)); 33593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(ebx, ebx); 33603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(not_zero, &has_mapped_parameters, Label::kNear); 33613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, Operand(edi, 33623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX))); 33633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(©, Label::kNear); 33643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&has_mapped_parameters); 33663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, Operand(edi, 33673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX))); 33683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(©); 33693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // eax = address of new object (tagged) 33713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = mapped parameter count (tagged) 33723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 33733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edi = address of boilerplate object (tagged) 33743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = mapped parameter count (tagged) 33753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = parameter count (tagged) 33763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] = address of receiver argument 33773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy the JS object part. 33783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { 33793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, FieldOperand(edi, i)); 33803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(eax, i), edx); 33813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch } 33823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up the callee in-object property. 33843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); 33853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, Operand(esp, 4 * kPointerSize)); 33863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(eax, JSObject::kHeaderSize + 33873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsCalleeIndex * kPointerSize), 33883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch edx); 33893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Use the length (smi tagged) and set that as an in-object property too. 33913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); 33923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(eax, JSObject::kHeaderSize + 33933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsLengthIndex * kPointerSize), 33943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch ecx); 33953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 33963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up the elements pointer in the allocated arguments object. 33973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // If we allocated a parameter map, edi will point there, otherwise to the 33983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // backing store. 33993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edi, Operand(eax, Heap::kArgumentsObjectSize)); 34003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); 34013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 34023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // eax = address of new object (tagged) 34033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = mapped parameter count (tagged) 34043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 34053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edi = address of parameter map or backing store (tagged) 34063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = mapped parameter count (tagged) 34073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = parameter count (tagged) 34083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] = address of receiver argument 34093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Free a register. 34103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(eax); 34113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 34123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Initialize parameter map. If there are no mapped arguments, we're done. 34133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label skip_parameter_map; 34143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(ebx, ebx); 34153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(zero, &skip_parameter_map); 341680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 34173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kMapOffset), 34183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Immediate(FACTORY->non_strict_arguments_elements_map())); 34193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2)))); 34203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax); 34213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi); 34223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize)); 34233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax); 34243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 34253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy the parameter slots and the holes in the arguments. 34263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We need to fill in mapped_parameter_count slots. They index the context, 34273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // where parameters are stored in reverse order, at 34283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 34293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // The mapped parameter thus need to get indices 34303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS+parameter_count-1 .. 34313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count 34323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We loop from right to left. 34333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label parameters_loop, parameters_test; 34343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ push(ecx); 34353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(eax, Operand(esp, 2 * kPointerSize)); 34363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); 34373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(ebx, Operand(esp, 4 * kPointerSize)); 34383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(ebx, eax); 34393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ecx, FACTORY->the_hole_value()); 34403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, edi); 34413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize)); 34423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // eax = loop variable (tagged) 34433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ebx = mapping index (tagged) 34443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = the hole value 34453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edx = address of parameter map (tagged) 34463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edi = address of backing store (tagged) 34473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = argument count (tagged) 34483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] = address of new object (tagged) 34493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] = mapped parameter count (tagged) 34503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[16] = parameter count (tagged) 34513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[20] = address of receiver argument 34523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(¶meters_test, Label::kNear); 34533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 34543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(¶meters_loop); 34553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(eax, Immediate(Smi::FromInt(1))); 34563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx); 34573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx); 34583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(ebx, Immediate(Smi::FromInt(1))); 34593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(¶meters_test); 34603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(eax, eax); 34613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(not_zero, ¶meters_loop, Label::kNear); 34623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ pop(ecx); 34633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 34643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&skip_parameter_map); 34653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 34663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // ecx = argument count (tagged) 34673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // edi = address of backing store (tagged) 34683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] = address of new object (tagged) 34693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] = mapped parameter count (tagged) 34703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] = parameter count (tagged) 34713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[16] = address of receiver argument 34723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy arguments header and remaining slots (if there are any). 34733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kMapOffset), 34743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Immediate(FACTORY->fixed_array_map())); 34753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); 34763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 34773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label arguments_loop, arguments_test; 34783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(ebx, Operand(esp, 1 * kPointerSize)); 34793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edx, Operand(esp, 4 * kPointerSize)); 34803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(edx, ebx); // Is there a smarter way to do negative scaling? 34813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(edx, ebx); 34823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(&arguments_test, Label::kNear); 34833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 34843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&arguments_loop); 34853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(edx, Immediate(kPointerSize)); 34863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(eax, Operand(edx, 0)); 34873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax); 34883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(ebx, Immediate(Smi::FromInt(1))); 34893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 34903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&arguments_test); 34913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ebx, ecx); 34923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ j(less, &arguments_loop, Label::kNear); 34933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 34943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Restore. 34953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ pop(eax); // Address of arguments object. 34963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ pop(ebx); // Parameter count. 34973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 34983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Return and remove the on-stack parameters. 34993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ret(3 * kPointerSize); 35003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 35013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Do the runtime call to allocate the arguments object. 35023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&runtime); 35033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ pop(eax); // Remove saved parameter count. 35043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(Operand(esp, 1 * kPointerSize), ecx); // Patch argument count. 35053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); 35063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch} 35073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 35083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 35093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { 35103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[0] : return address 35113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[4] : number of parameters 35123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[8] : receiver displacement 35133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // esp[12] : function 351480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 351580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the calling frame is an arguments adaptor frame. 351680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label adaptor_frame, try_allocate, runtime; 351780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 351880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 35193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 352069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(equal, &adaptor_frame, Label::kNear); 352180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 352280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the length from the frame. 352380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esp, 1 * kPointerSize)); 352469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&try_allocate, Label::kNear); 352580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 352680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Patch the arguments.length and the parameters pointer. 352780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&adaptor_frame); 352880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 352980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 1 * kPointerSize), ecx); 35303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edx, Operand(edx, ecx, times_2, 35313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch StandardFrameConstants::kCallerSPOffset)); 353280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 2 * kPointerSize), edx); 353380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 353480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try the new space allocation. Start out with computing the size of 353580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the arguments object and the elements array. 3536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label add_arguments_object; 353780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&try_allocate); 35383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(ecx, ecx); 3539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &add_arguments_object, Label::kNear); 354080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize)); 354180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&add_arguments_object); 35423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(ecx, Immediate(Heap::kArgumentsObjectSizeStrict)); 354380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 354480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the allocation of both objects in one go. 354580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT); 354680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 354780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the arguments boilerplate from the current (global) context. 354880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 354980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); 35503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int offset = 35513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX); 35523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(edi, Operand(edi, offset)); 355380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 355480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy the JS object part. 355580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { 355680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(edi, i)); 355780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, i), ebx); 355880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 355980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 356080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the length (smi tagged) and set that as an in-object property too. 356144f0eee88ff00398ff7f715fab053374d808c90dSteve Block STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); 356280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esp, 1 * kPointerSize)); 356344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(FieldOperand(eax, JSObject::kHeaderSize + 35643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsLengthIndex * kPointerSize), 356544f0eee88ff00398ff7f715fab053374d808c90dSteve Block ecx); 356680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 356780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If there are no actual arguments, we're done. 356880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label done; 35693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(ecx, ecx); 357069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &done, Label::kNear); 357180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 357280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the parameters pointer from the stack. 357380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 2 * kPointerSize)); 357480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 35753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up the elements pointer in the allocated arguments object and 357680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // initialize the header in the elements fixed array. 35773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict)); 357880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); 357980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(edi, FixedArray::kMapOffset), 35803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Immediate(FACTORY->fixed_array_map())); 358144f0eee88ff00398ff7f715fab053374d808c90dSteve Block 358280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); 358380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Untag the length for the loop below. 358480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ecx); 358580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 358680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy the fixed array slots. 3587257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop; 358880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 358980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(edx, -1 * kPointerSize)); // Skip receiver. 359080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx); 35913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(edi, Immediate(kPointerSize)); 35923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(edx, Immediate(kPointerSize)); 359380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ dec(ecx); 359480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &loop); 359580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 359680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameters. 359780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 359880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 359980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 360080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the runtime call to allocate the arguments object. 360180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 36023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); 360380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 360480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 360580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 360680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid RegExpExecStub::Generate(MacroAssembler* masm) { 360780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump directly to runtime if native RegExp is not selected at compile 360880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // time or if regexp entry in generated code is turned off runtime switch or 360980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // at compilation. 361080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef V8_INTERPRETED_REGEXP 361180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 361280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else // V8_INTERPRETED_REGEXP 361380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 361480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 361580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[0]: return address 361680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[4]: last_match_info (expected JSArray) 361780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[8]: previous index 361880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[12]: subject string 361980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[16]: JSRegExp object 362080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 362180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kLastMatchInfoOffset = 1 * kPointerSize; 362280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kPreviousIndexOffset = 2 * kPointerSize; 362380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kSubjectOffset = 3 * kPointerSize; 362480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kJSRegExpOffset = 4 * kPointerSize; 362580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 362680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime, invoke_regexp; 362780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 362880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Ensure that a RegExp stack is allocated. 362980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference address_of_regexp_stack_memory_address = 363044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_regexp_stack_memory_address( 363144f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 363280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference address_of_regexp_stack_memory_size = 363344f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_regexp_stack_memory_size(masm->isolate()); 363480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); 36353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(ebx, ebx); 3636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &runtime); 363780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 363880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the first argument is a JSRegExp object. 363980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kJSRegExpOffset)); 364080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 36413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &runtime); 364280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); 364380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 364480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the RegExp has been compiled (data contains a fixed array). 364580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); 364680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 364780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Immediate(kSmiTagMask)); 364880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected"); 364980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); 365080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); 365180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 365280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 365380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 365480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. 365580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset)); 36563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ebx, Immediate(Smi::FromInt(JSRegExp::IRREGEXP))); 365780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 365880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 365980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 366080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the number of captures fit in the static offsets vector buffer. 366180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); 366280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate number of capture registers (number_of_captures + 1) * 2. This 366380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // uses the asumption that smis are 2 * their untagged value. 366480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 366580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 36663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(edx, Immediate(2)); // edx was a smi. 366780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the static offsets vector buffer is large enough. 366880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize); 366980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above, &runtime); 367080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 367180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 367280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: Number of capture registers 367380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the second argument is a string. 367480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kSubjectOffset)); 36753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &runtime); 367680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); 367780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(NegateCondition(is_string), &runtime); 367880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the length of the string to ebx. 367980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); 368080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 368180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: Length of subject string as a smi 368280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 368380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: Number of capture registers 368480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the third argument is a positive smi less than the subject 368580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // string length. A negative value will be greater (unsigned comparison). 368680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kPreviousIndexOffset)); 36873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(eax, &runtime); 36883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(eax, ebx); 368980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &runtime); 369080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 369180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 369280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: Number of capture registers 369380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the fourth object is a JSArray object. 369480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kLastMatchInfoOffset)); 36953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &runtime); 369680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); 369780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 369880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the JSArray is in fast case. 369980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); 370080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset)); 370144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 370244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, factory->fixed_array_map()); 370380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 370480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the last match info has space for the capture registers and the 370580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // additional information. 370680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset)); 370780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(eax); 37083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(edx, Immediate(RegExpImpl::kLastMatchOverhead)); 37093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(edx, eax); 371080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(greater, &runtime); 371180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 371269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Reset offset for possibly sliced string. 371369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(edi, Immediate(0)); 371480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 371580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the representation and encoding of the subject string. 371680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label seq_ascii_string, seq_two_byte_string, check_code; 371780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kSubjectOffset)); 371880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 371980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 372080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // First check for flat two byte string. 37213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(ebx, kIsNotStringMask | 37223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kStringRepresentationMask | 37233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kStringEncodingMask | 37243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kShortExternalStringMask); 372580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); 372669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &seq_two_byte_string, Label::kNear); 37273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Any other flat string must be a flat ASCII string. None of the following 37283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // string type tests will succeed if subject is not a string or a short 37293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // external string. 37303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(ebx, Immediate(kIsNotStringMask | 37313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kStringRepresentationMask | 37323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kShortExternalStringMask)); 373369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &seq_ascii_string, Label::kNear); 373480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 37353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ebx: whether subject is a string and if yes, its string representation 373669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Check for flat cons string or sliced string. 373780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // A flat cons string is a cons string where the second part is the empty 373880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // string. In that case the subject string is just the first part of the cons 373980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // string. Also in this case the first part of the cons string is known to be 374080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // a sequential string or an external string. 374169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // In the case of a sliced string its offset has to be taken into account. 37423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label cons_string, external_string, check_encoding; 374369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kConsStringTag < kExternalStringTag); 374469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); 37453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); 37463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); 37473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ebx, Immediate(kExternalStringTag)); 374869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(less, &cons_string); 37493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(equal, &external_string); 37503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 37513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Catch non-string subject or short external string. 37523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); 37533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(ebx, Immediate(kIsNotStringMask | kShortExternalStringTag)); 37543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_zero, &runtime); 375569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 375669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // String is sliced. 375769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset)); 375869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset)); 375969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // edi: offset of sliced string, smi-tagged. 376069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // eax: parent string. 376169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&check_encoding, Label::kNear); 376269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // String is a cons string, check whether it is flat. 376369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&cons_string); 376469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(FieldOperand(eax, ConsString::kSecondOffset), factory->empty_string()); 376580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 376680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); 376769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&check_encoding); 376880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 376969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // eax: first part of cons string or parent of sliced string. 377069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // ebx: map of first part of cons string or map of parent of sliced string. 377169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Is first part of cons or parent of slice a flat two byte string? 377280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), 377380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen kStringRepresentationMask | kStringEncodingMask); 377480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); 377569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &seq_two_byte_string, Label::kNear); 37763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Any other flat string must be sequential ASCII or external. 377780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), 377880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen kStringRepresentationMask); 37793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_zero, &external_string); 378080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 378180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&seq_ascii_string); 37823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // eax: subject string (flat ASCII) 378380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 378480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset)); 37853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Set(ecx, Immediate(1)); // Type is ASCII. 378669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&check_code, Label::kNear); 378780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 378880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&seq_two_byte_string); 378980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: subject string (flat two byte) 379080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: RegExp data (FixedArray) 379180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset)); 379269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Set(ecx, Immediate(0)); // Type is two byte. 379380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 379480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_code); 379580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the irregexp code has been generated for the actual string 379680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // encoding. If it has, the field contains a code object otherwise it contains 3797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // a smi (code flushing support). 3798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfSmi(edx, &runtime); 379980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 380080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: subject string 380180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: code 38023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ecx: encoding of subject string (1 if ASCII, 0 if two_byte); 380380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load used arguments before starting to push arguments for call to native 380480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // RegExp code to avoid handling changing stack height. 380580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(esp, kPreviousIndexOffset)); 380680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ebx); // Previous index from smi. 380780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 380880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: subject string 380980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: previous index 381080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: code 38113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ecx: encoding of subject string (1 if ASCII 0 if two_byte); 381280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // All checks done. Now push arguments for native regexp code. 381344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 381444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->regexp_entry_native(), 1); 381580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 381644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Isolates: note we add an additional parameter here (isolate pointer). 381744f0eee88ff00398ff7f715fab053374d808c90dSteve Block static const int kRegExpExecuteArguments = 8; 3818e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ EnterApiExitFrame(kRegExpExecuteArguments); 381980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 382044f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Argument 8: Pass current isolate address. 382144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(Operand(esp, 7 * kPointerSize), 382244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(ExternalReference::isolate_address())); 382344f0eee88ff00398ff7f715fab053374d808c90dSteve Block 382480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 7: Indicate that this is a direct call from JavaScript. 382580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 6 * kPointerSize), Immediate(1)); 382680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 382780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 6: Start (high end) of backtracking stack memory area. 382869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(esi, Operand::StaticVariable(address_of_regexp_stack_memory_address)); 382969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ add(esi, Operand::StaticVariable(address_of_regexp_stack_memory_size)); 383069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(Operand(esp, 5 * kPointerSize), esi); 383180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 383280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 5: static offsets vector buffer. 383380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 4 * kPointerSize), 383444f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(ExternalReference::address_of_static_offsets_vector( 383544f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()))); 383680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 383769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Argument 2: Previous index. 383869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(Operand(esp, 1 * kPointerSize), ebx); 383969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 384069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Argument 1: Original subject string. 384169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // The original subject is in the previous stack frame. Therefore we have to 384269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // use ebp, which points exactly to one pointer size below the previous esp. 384369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // (Because creating a new stack frame pushes the previous ebp onto the stack 384469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // and thereby moves up esp by one kPointerSize.) 384569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(esi, Operand(ebp, kSubjectOffset + kPointerSize)); 384669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(Operand(esp, 0 * kPointerSize), esi); 384769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 384869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // esi: original subject string 384969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // eax: underlying subject string 385069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // ebx: previous index 38513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ecx: encoding of subject string (1 if ASCII 0 if two_byte); 385269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // edx: code 385380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 4: End of string data 385480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 3: Start of string data 385569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Prepare start and end index of the input. 385669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Load the length from the original sliced string if that is the case. 385769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(esi, FieldOperand(esi, String::kLengthOffset)); 38583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(esi, edi); // Calculate input end wrt offset. 385969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ SmiUntag(edi); 38603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(ebx, edi); // Calculate input start wrt offset. 386169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 386269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // ebx: start index of the input string 386369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // esi: end index of the input string 3864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label setup_two_byte, setup_rest; 38653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(ecx, ecx); 3866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &setup_two_byte, Label::kNear); 386769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ SmiUntag(esi); 386869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ lea(ecx, FieldOperand(eax, esi, times_1, SeqAsciiString::kHeaderSize)); 386980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. 387080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); 387180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. 3872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&setup_rest, Label::kNear); 387380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 387480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&setup_two_byte); 387580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 387669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kSmiTagSize == 1); // esi is smi (powered by 2). 387769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize)); 387880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. 387980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); 388080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. 388180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 388280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&setup_rest); 388380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 388480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate the code entry and call it. 38853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag)); 38863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ call(edx); 3887e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3888e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Drop arguments and come back to JS mode. 3889e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LeaveApiExitFrame(); 389080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 389180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the result. 389280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label success; 389380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS); 3894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &success); 389580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label failure; 389680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); 3897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &failure); 389880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); 389980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If not exception it can only be retry. Handle that in the runtime system. 390080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &runtime); 390180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result must now be exception. If there is no pending exception already a 390280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stack overflow (on the backtrack stack) was detected in RegExp code but 390380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // haven't created the exception yet. Handle that in the runtime system. 390480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // TODO(592): Rerunning the RegExp to get the stack overflow exception. 3905589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch ExternalReference pending_exception(Isolate::kPendingExceptionAddress, 390644f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 39073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value())); 3908e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(eax, Operand::StaticVariable(pending_exception)); 39093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(edx, eax); 391080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &runtime); 3911e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // For exception, throw the exception again. 3912e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3913e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Clear the pending exception variable. 3914e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(Operand::StaticVariable(pending_exception), edx); 3915e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3916e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Special handling of termination exceptions which are uncatchable 3917e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // by javascript code. 391844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, factory->termination_exception()); 3919e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label throw_termination_exception; 392069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(equal, &throw_termination_exception, Label::kNear); 3921e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3922e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Handle normal exception by following handler chain. 3923e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Throw(eax); 3924e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3925e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&throw_termination_exception); 39263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ThrowUncatchable(eax); 3927e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 392880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&failure); 3929e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // For failure to match, return null. 39303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(eax, factory->null_value()); 393180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(4 * kPointerSize); 393280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 393380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load RegExp data. 393480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&success); 393580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kJSRegExpOffset)); 393680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); 393780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); 393880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate number of capture registers (number_of_captures + 1) * 2. 393980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 394080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 39413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(edx, Immediate(2)); // edx was a smi. 394280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 394380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: Number of capture registers 394480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load last_match_info which is still known to be a fast case JSArray. 394580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kLastMatchInfoOffset)); 394680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); 394780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 394880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: last_match_info backing store (FixedArray) 394980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: number of capture registers 395080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store the capture count. 395180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(edx); // Number of capture registers to smi. 395280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ebx, RegExpImpl::kLastCaptureCountOffset), edx); 395380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edx); // Number of capture registers back from smi. 395480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store last subject and last input. 395580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kSubjectOffset)); 395680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax); 39573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ RecordWriteField(ebx, 39583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch RegExpImpl::kLastSubjectOffset, 39593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch eax, 39603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch edi, 39613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kDontSaveFPRegs); 396280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kSubjectOffset)); 396380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax); 39643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ RecordWriteField(ebx, 39653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch RegExpImpl::kLastInputOffset, 39663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch eax, 39673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch edi, 39683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kDontSaveFPRegs); 396980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 397080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the static offsets vector filled by the native regexp code. 397180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference address_of_static_offsets_vector = 397244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_static_offsets_vector(masm->isolate()); 397380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(address_of_static_offsets_vector)); 397480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 397580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: last_match_info backing store (FixedArray) 397680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: offsets vector 397780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: number of capture registers 3978257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label next_capture, done; 397980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Capture register counter starts from number of capture registers and 398080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // counts down until wraping after zero. 398180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&next_capture); 39823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(edx, Immediate(1)); 3983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(negative, &done, Label::kNear); 398480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the value from the static offsets vector buffer. 398580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, Operand(ecx, edx, times_int_size, 0)); 398680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(edi); 398780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store the smi value in the last match info. 398880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ebx, 398980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen edx, 399080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_pointer_size, 399180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen RegExpImpl::kFirstCaptureOffset), 399280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen edi); 399380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&next_capture); 399480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 399580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 399680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return last match info. 399780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, kLastMatchInfoOffset)); 399880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(4 * kPointerSize); 399980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 40003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // External string. Short external strings have already been ruled out. 40013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // eax: subject string (expected to be external) 40023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ebx: scratch 40033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&external_string); 40043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 40053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 40063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (FLAG_debug_code) { 40073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Assert that we do not have a cons or slice (indirect strings) here. 40083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Sequential strings have already been ruled out. 40093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test_b(ebx, kIsIndirectStringMask); 40103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Assert(zero, "external string expected, but not found"); 40113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 40123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset)); 40133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Move the pointer so that offset-wise, it looks like a sequential string. 40143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); 40153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(eax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 40163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kTwoByteStringTag == 0); 40173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test_b(ebx, kStringEncodingMask); 40183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_zero, &seq_ascii_string); 40193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&seq_two_byte_string); 40203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 402180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the runtime call to execute the regexp. 402280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 402380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 402480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif // V8_INTERPRETED_REGEXP 402580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 402680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 402780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4028b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid RegExpConstructResultStub::Generate(MacroAssembler* masm) { 4029b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const int kMaxInlineLength = 100; 4030b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label slowcase; 4031257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done; 4032b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ebx, Operand(esp, kPointerSize * 3)); 40333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(ebx, &slowcase); 40343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ebx, Immediate(Smi::FromInt(kMaxInlineLength))); 4035b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(above, &slowcase); 4036b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Smi-tagging is equivalent to multiplying by 2. 4037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 4038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTagSize == 1); 4039b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate RegExpResult followed by FixedArray with size in ebx. 4040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // JSArray: [Map][empty properties][Elements][Length-smi][index][input] 4041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Elements: [Map][Length][..elements..] 4042b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize, 4043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch times_half_pointer_size, 4044b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ebx, // In: Number of elements (times 2, being a smi) 4045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch eax, // Out: Start of allocation (tagged). 4046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ecx, // Out: End of allocation. 4047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch edx, // Scratch register 4048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch &slowcase, 4049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch TAG_OBJECT); 4050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax: Start of allocated area, object-tagged. 4051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set JSArray map to global.regexp_result_map(). 4053b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set empty properties FixedArray. 4054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set elements to point to FixedArray allocated right after the JSArray. 4055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Interleave operations for better latency. 4056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX)); 405744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 405844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(ecx, Immediate(factory->empty_fixed_array())); 4059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ lea(ebx, Operand(eax, JSRegExpResult::kSize)); 4060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset)); 4061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx); 4062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx); 4063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX)); 4064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, HeapObject::kMapOffset), edx); 4065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set input, index and length fields from arguments. 4067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(esp, kPointerSize * 1)); 4068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSRegExpResult::kInputOffset), ecx); 4069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(esp, kPointerSize * 2)); 4070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSRegExpResult::kIndexOffset), ecx); 4071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Operand(esp, kPointerSize * 3)); 4072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(eax, JSArray::kLengthOffset), ecx); 4073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill out the elements FixedArray. 4075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax: JSArray. 4076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ebx: FixedArray. 4077b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ecx: Number of elements in array, as smi. 4078b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4079b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set map. 4080b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(ebx, HeapObject::kMapOffset), 408144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(factory->fixed_array_map())); 4082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set length. 4083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(FieldOperand(ebx, FixedArray::kLengthOffset), ecx); 4084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill contents of fixed-array with the-hole. 4085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiUntag(ecx); 408644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(edx, Immediate(factory->the_hole_value())); 4087b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize)); 4088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill fixed array elements with hole. 4089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // eax: JSArray. 4090b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ecx: Number of elements to fill. 4091b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ebx: Start of elements in FixedArray. 4092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // edx: the hole. 4093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label loop; 40943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(ecx, ecx); 4095b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&loop); 4096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(less_equal, &done, Label::kNear); // Jump if ecx is negative or zero. 40973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(ecx, Immediate(1)); 4098b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(Operand(ebx, ecx, times_pointer_size, 0), edx); 4099b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&loop); 4100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4101b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&done); 4102b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(3 * kPointerSize); 4103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4104b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&slowcase); 4105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); 4106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 4107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 410980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, 411080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register object, 411180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register result, 411280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 411380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 411480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool object_is_smi, 411580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_found) { 411680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Use of registers. Register result is used as a temporary. 411780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register number_string_cache = result; 411880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register mask = scratch1; 411980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch = scratch2; 412080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 412180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the number string cache. 41223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference roots_array_start = 41233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference::roots_array_start(masm->isolate()); 412480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex)); 412580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(number_string_cache, 41263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Operand::StaticArray(scratch, times_pointer_size, roots_array_start)); 412780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make the hash mask from the length of the number string cache. It 412880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // contains two elements (number and string) for each cache entry. 412980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset)); 413080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shr(mask, kSmiTagSize + 1); // Untag length and divide it by two. 41313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(mask, Immediate(1)); // Make mask. 413280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 413380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate the entry in the number string cache. The hash value in the 413480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // number string cache for smis is just the smi value, and the hash for 413580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // doubles is the xor of the upper and lower words. See 413680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Heap::GetNumberStringCache. 4137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label smi_hash_calculated; 4138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label load_result_from_cache; 413980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (object_is_smi) { 414080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, object); 414180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 414280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 4143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_smi; 414480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 41453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(object, ¬_smi, Label::kNear); 414680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, object); 414780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(scratch); 4148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&smi_hash_calculated, Label::kNear); 414980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_smi); 415080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(object, HeapObject::kMapOffset), 415144f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()->factory()->heap_number_map()); 415280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_found); 415380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(8 == kDoubleSize); 415480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset)); 415580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); 415680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Object is heap number and hash is now in scratch. Calculate cache index. 41573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(scratch, mask); 415880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register index = scratch; 415980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register probe = mask; 416080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(probe, 416180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(number_string_cache, 416280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index, 416380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_twice_pointer_size, 416480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize)); 41653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(probe, not_found); 41668b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 416780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope fscope(SSE2); 416880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset)); 416980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset)); 417080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ucomisd(xmm0, xmm1); 417180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 417280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(object, HeapNumber::kValueOffset)); 417380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset)); 417480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ FCmp(); 417580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 417680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(parity_even, not_found); // Bail out if NaN is involved. 417780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_found); // The cache did not contain this value. 4178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&load_result_from_cache, Label::kNear); 417980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 418080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 418180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&smi_hash_calculated); 418280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Object is smi and hash is now in scratch. Calculate cache index. 41833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(scratch, mask); 418480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register index = scratch; 418580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the entry is the smi we are looking for. 418680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(object, 418780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(number_string_cache, 418880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index, 418980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_twice_pointer_size, 419080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize)); 419180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, not_found); 419280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 419380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the result from the cache. 419480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_result_from_cache); 419580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result, 419680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(number_string_cache, 419780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index, 419880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_twice_pointer_size, 419980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize + kPointerSize)); 420044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 420144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->number_to_string_native(), 1); 420280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 420380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 420480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 420580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::Generate(MacroAssembler* masm) { 420680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 420780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 420880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, Operand(esp, kPointerSize)); 420980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 421080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Generate code to lookup number in the number string cache. 421180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateLookupNumberStringCache(masm, ebx, eax, ecx, edx, false, &runtime); 421280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(1 * kPointerSize); 421380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 421480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 421580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle number to string in the runtime system if not found in the cache. 421680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1); 421780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 421880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 421980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 422080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic int NegativeComparisonResult(Condition cc) { 422180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(cc != equal); 422280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT((cc == less) || (cc == less_equal) 422380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen || (cc == greater) || (cc == greater_equal)); 422480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return (cc == greater || cc == greater_equal) ? LESS : GREATER; 422580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 422680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 422780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::Generate(MacroAssembler* masm) { 422880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 422980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 423069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label check_unequal_objects; 423180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 42320d5e116f6aee03185f237311a943491bb079a768Kristian Monsen // Compare two smis if required. 42330d5e116f6aee03185f237311a943491bb079a768Kristian Monsen if (include_smi_compare_) { 42340d5e116f6aee03185f237311a943491bb079a768Kristian Monsen Label non_smi, smi_done; 42353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, edx); 42363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ or_(ecx, eax); 423769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfNotSmi(ecx, &non_smi, Label::kNear); 42383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(edx, eax); // Return on the result of the subtraction. 423969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(no_overflow, &smi_done, Label::kNear); 4240f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch __ not_(edx); // Correct sign in case of overflow. edx is never 0 here. 42410d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ bind(&smi_done); 42420d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ mov(eax, edx); 42430d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ ret(0); 42440d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ bind(&non_smi); 42450d5e116f6aee03185f237311a943491bb079a768Kristian Monsen } else if (FLAG_debug_code) { 42463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, edx); 42473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ or_(ecx, eax); 42480d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ test(ecx, Immediate(kSmiTagMask)); 42490d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ Assert(not_zero, "Unexpected smi operands."); 42500d5e116f6aee03185f237311a943491bb079a768Kristian Monsen } 42510d5e116f6aee03185f237311a943491bb079a768Kristian Monsen 425280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NOTICE! This code is only reached after a smi-fast-case check, so 425380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // it is certain that at least one operand isn't a smi. 425480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 425580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Identical objects can be compared fast, but there are some tricky cases 425680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // for NaN and undefined. 425780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen { 425880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label not_identical; 42593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(eax, edx); 426080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, ¬_identical); 426180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 426280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ != equal) { 426380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for undefined. undefined OP undefined is false even though 426480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // undefined == undefined. 4265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label check_for_nan; 426644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(edx, masm->isolate()->factory()->undefined_value()); 4267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &check_for_nan, Label::kNear); 426880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); 426980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 427080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_for_nan); 427180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 427280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 427344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Test for NaN. Sadly, we can't just compare to factory->nan_value(), 427480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // so we do the second best thing - test it ourselves. 427580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Note: if cc_ != equal, never_nan_nan_ is not used. 427680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (never_nan_nan_ && (cc_ == equal)) { 427780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 427880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 427980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 4280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label heap_number; 428180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(edx, HeapObject::kMapOffset), 428244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(masm->isolate()->factory()->heap_number_map())); 4283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &heap_number, Label::kNear); 428480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ != equal) { 428580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call runtime on identical JSObjects. Otherwise return equal. 42863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); 428780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, ¬_identical); 428880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 428980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 429080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 429180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 429280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&heap_number); 429380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // It is a heap number, so return non-equal if it's NaN and equal if 429480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // it's not NaN. 429580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The representation of NaN values has all exponent bits (52..62) set, 429680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and not all mantissa bits (0..51) clear. 429780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We only accept QNaNs, which have bit 51 set. 429880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read top bits of double representation (second word of value). 429980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 430080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., 430180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // all bits in the mask are set. We only need to check the word 430280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // that contains the exponent and high bit of the mantissa. 430380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0); 430480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); 43059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Set(eax, Immediate(0)); 430680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Shift value and mask so kQuietNaNHighBitsMask applies to topmost 430780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // bits. 43083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(edx, edx); 430980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edx, kQuietNaNHighBitsMask << 1); 431080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal) { 431180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(EQUAL != 1); 431280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ setcc(above_equal, eax); 431380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 431480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 4315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label nan; 4316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above_equal, &nan, Label::kNear); 431780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 431880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 431980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&nan); 432080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); 432180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 432280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 432380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 432480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 432580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_identical); 432680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 432780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 432880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Strict equality can quickly decide whether objects are equal. 432980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Non-strict object equality is slower, so it is handled later in the stub. 433080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal && strict_) { 433180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow; // Fallthrough label. 4332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_smis; 433380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If we're doing a strict equality comparison, we don't have to do 433480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // type conversion, so we generate code to do fast comparison for objects 433580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and oddballs. Non-smi numbers and strings still go through the usual 433680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // slow-case code. 433780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If either is a Smi (we know that not both are), then they can only 433880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // be equal if the other is a HeapNumber. If so, use the slow case. 433980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 434080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT_EQ(0, Smi::FromInt(0)); 434180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(kSmiTagMask)); 43423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(ecx, eax); 43433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(ecx, edx); 4344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, ¬_smis, Label::kNear); 434580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // One operand is a smi. 434680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 434780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check whether the non-smi is a heap number. 434880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagMask == 1); 434980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx still holds eax & kSmiTag, which is either zero or one. 43503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(ecx, Immediate(0x01)); 435180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, edx); 43523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(ebx, eax); 43533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(ebx, ecx); // ebx holds either 0 or eax ^ edx. 43543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(ebx, eax); 435580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // if eax was smi, ebx is now edx, else eax. 435680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 435780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the non-smi operand is a heap number. 435880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), 435944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(masm->isolate()->factory()->heap_number_map())); 436080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If heap number, handle it in the slow case. 436169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(equal, &slow, Label::kNear); 436280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return non-equal (ebx is not zero) 436380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, ebx); 436480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 436580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 436680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_smis); 436780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If either operand is a JSObject or an oddball value, then they are not 436880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // equal since their pointers are different 436980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // There is no test for undetectability in strict equality. 437080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 437180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the type of the first operand. 437280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the first object is a JS object, we have done pointer comparison. 4373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label first_non_object; 43743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); 43753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); 4376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, &first_non_object, Label::kNear); 437780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 437880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return non-zero (eax is not zero) 4379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label return_not_equal; 438080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kHeapObjectTag != 0); 438180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&return_not_equal); 438280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 438380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 438480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&first_non_object); 438580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for oddballs: true, false, null, undefined. 438680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpInstanceType(ecx, ODDBALL_TYPE); 438780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &return_not_equal); 438880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 43893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ecx); 439080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, &return_not_equal); 439180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 439280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for oddballs: true, false, null, undefined. 439380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpInstanceType(ecx, ODDBALL_TYPE); 439480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &return_not_equal); 439580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 439680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fall through to the general case. 439780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 439880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 439980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 440080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Generate the number comparison code. 440180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (include_number_compare_) { 440280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_number_comparison; 440380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label unordered; 44048b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2)) { 440580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope use_sse2(SSE2); 440680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope use_cmov(CMOV); 440780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 440880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); 440980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ucomisd(xmm0, xmm1); 441080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 441180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Don't base result on EFLAGS when a NaN is involved. 441269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(parity_even, &unordered, Label::kNear); 441380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return a result of -1, 0, or 1, based on EFLAGS. 441480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, 0); // equal 441580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(Smi::FromInt(1))); 44163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmov(above, eax, ecx); 441780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Immediate(Smi::FromInt(-1))); 44183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmov(below, eax, ecx); 441980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 442080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 442180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FloatingPointHelper::CheckFloatOperands( 442280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen masm, &non_number_comparison, ebx); 442380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FloatingPointHelper::LoadFloatOperand(masm, eax); 442480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FloatingPointHelper::LoadFloatOperand(masm, edx); 442580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ FCmp(); 442680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 442780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Don't base result on EFLAGS when a NaN is involved. 442869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(parity_even, &unordered, Label::kNear); 442980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label below_label, above_label; 443180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return a result of -1, 0, or 1, based on EFLAGS. 443269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(below, &below_label, Label::kNear); 443369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(above, &above_label, Label::kNear); 443480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 44359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Set(eax, Immediate(0)); 443680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 443780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 443880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&below_label); 443980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(Smi::FromInt(-1))); 444080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 444180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 444280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&above_label); 444380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(Smi::FromInt(1))); 444480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 444580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 444680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 444780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If one of the numbers was NaN, then the result is always false. 444880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The cc is never not-equal. 444980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&unordered); 445080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(cc_ != not_equal); 445180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == less || cc_ == less_equal) { 445280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(Smi::FromInt(1))); 445380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 445480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(Smi::FromInt(-1))); 445580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 445680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 445780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 445880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The number comparison code did not provide a valid result. 445980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_number_comparison); 446080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 446180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 446280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fast negative check for symbol-to-symbol equality. 446380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label check_for_strings; 446480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal) { 446580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); 446680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); 446780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 446880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We've already checked for object identity, so if both operands 446980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // are symbols they aren't equal. Register eax already holds a 447080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // non-zero value, which indicates not equal, so just return. 447180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 447280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 447380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 447480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_for_strings); 447580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 447680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, 447780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &check_unequal_objects); 447880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 44793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Inline comparison of ASCII strings. 4480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (cc_ == equal) { 4481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringCompareStub::GenerateFlatAsciiStringEquals(masm, 448280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen edx, 448380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen eax, 448480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ecx, 4485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ebx); 4486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 4487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringCompareStub::GenerateCompareFlatAsciiStrings(masm, 4488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch edx, 4489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch eax, 4490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ecx, 4491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ebx, 4492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch edi); 4493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 449480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG 449580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fall-through from string comparison"); 449680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 449780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 449880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_unequal_objects); 449980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal && !strict_) { 450080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Non-strict equality. Objects are unequal if 450180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // they are both JSObjects and not undetectable, 450280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and their pointers are different. 4503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_both_objects; 4504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label return_unequal; 450580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // At most one is a smi, so we can test for smi by adding the two. 450680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // A smi plus a heap object has the low bit set, a heap object plus 450780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // a heap object has the low bit clear. 450880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 450980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagMask == 1); 451080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(eax, edx, times_1, 0)); 451180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Immediate(kSmiTagMask)); 4512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, ¬_both_objects, Label::kNear); 45133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); 4514257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, ¬_both_objects, Label::kNear); 45153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx); 4516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(below, ¬_both_objects, Label::kNear); 451780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We do not bail out after this point. Both are JSObjects, and 451880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // they are equal if and only if both are undetectable. 451980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The and of the undetectable flags is 1 if and only if they are equal. 452080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 452180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1 << Map::kIsUndetectable); 4522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &return_unequal, Label::kNear); 452380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test_b(FieldOperand(ebx, Map::kBitFieldOffset), 452480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1 << Map::kIsUndetectable); 4525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &return_unequal, Label::kNear); 452680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The objects are both undetectable, so they both compare as the value 452780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // undefined, and are equal. 452880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(EQUAL)); 452980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&return_unequal); 453080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return non-equal by returning the non-zero object pointer in eax, 453180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // or return equal if we fell through to here. 453280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); // rax, rdx were pushed 453380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_both_objects); 453480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 453580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 453680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Push arguments below the return address. 453780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ecx); 453880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(edx); 453980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(eax); 454080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 454180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Figure out which native to call and setup the arguments. 454280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Builtins::JavaScript builtin; 454380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == equal) { 454480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; 454580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 454680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen builtin = Builtins::COMPARE; 454780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); 454880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 454980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 455080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore return address on the stack. 455180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ecx); 455280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 455380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) 455480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // tagged as a small integer. 455580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ InvokeBuiltin(builtin, JUMP_FUNCTION); 455680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 455780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 455880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 455980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::BranchIfNonSymbol(MacroAssembler* masm, 456080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* label, 456180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register object, 456280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 45633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(object, label); 456480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset)); 456580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); 456680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(scratch, kIsSymbolMask | kIsNotStringMask); 456780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(scratch, kSymbolTag | kStringTag); 456880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, label); 456980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 457080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 457180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 457280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StackCheckStub::Generate(MacroAssembler* masm) { 4573f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch __ TailCallRuntime(Runtime::kStackGuard, 0, 1); 457480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 457580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 457680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 45773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid InterruptStub::Generate(MacroAssembler* masm) { 45783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kInterrupt, 0, 1); 45793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 45803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 45813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 45823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic void GenerateRecordCallTarget(MacroAssembler* masm) { 45833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Cache the called function in a global property cell. Cache states 45843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // are uninitialized, monomorphic (indicated by a JSFunction), and 45853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // megamorphic. 45863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ebx : cache cell for call target 45873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // edi : the function to call 45883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Isolate* isolate = masm->isolate(); 45893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label initialize, done; 45903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 45913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load the cache state into ecx. 45923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); 45933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 45943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // A monomorphic cache hit or an already megamorphic state: invoke the 45953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // function without changing the state. 45963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ecx, edi); 45973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(equal, &done, Label::kNear); 45983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ecx, Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate))); 45993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(equal, &done, Label::kNear); 46003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 46013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // A monomorphic miss (i.e, here the cache is not uninitialized) goes 46023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // megamorphic. 46033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ecx, Immediate(TypeFeedbackCells::UninitializedSentinel(isolate))); 46043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(equal, &initialize, Label::kNear); 46053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // MegamorphicSentinel is an immortal immovable object (undefined) so no 46063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // write-barrier is needed. 46073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), 46083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate))); 46093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&done, Label::kNear); 46103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 46113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // An uninitialized cache is patched with the function. 46123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&initialize); 46133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), edi); 46143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // No need for a write barrier here - cells are rescanned. 46153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 46163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&done); 46173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 46183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 46193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 462080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CallFunctionStub::Generate(MacroAssembler* masm) { 46213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ebx : cache cell for call target 46223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // edi : the function to call 46233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Isolate* isolate = masm->isolate(); 4624589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Label slow, non_function; 462580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // The receiver might implicitly be the global object. This is 4627257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // indicated by passing the hole as the receiver to the call 4628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // function stub. 4629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (ReceiverMightBeImplicit()) { 46303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label receiver_ok; 463180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the receiver from the stack. 463280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // +1 ~ return address 463380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, (argc_ + 1) * kPointerSize)); 4634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Call as function is indicated with the hole. 46353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(eax, isolate->factory()->the_hole_value()); 46363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &receiver_ok, Label::kNear); 4637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Patch the receiver on the stack with the global receiver object. 46383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, GlobalObjectOperand()); 46393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); 46403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(Operand(esp, (argc_ + 1) * kPointerSize), ecx); 46413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&receiver_ok); 464280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 464380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 464480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the function really is a JavaScript function. 4645589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ JumpIfSmi(edi, &non_function); 464680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Goto slow case if we do not have a function. 464780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 4648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &slow); 464980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 46503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (RecordCallTarget()) { 46513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateRecordCallTarget(masm); 46523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 46533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 465480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fast-case: Just invoke the function. 465580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ParameterCount actual(argc_); 4656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 4657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (ReceiverMightBeImplicit()) { 4658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label call_as_function; 46593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(eax, isolate->factory()->the_hole_value()); 4660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &call_as_function); 4661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeFunction(edi, 4662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch actual, 4663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch JUMP_FUNCTION, 4664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch NullCallWrapper(), 4665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CALL_AS_METHOD); 4666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_as_function); 4667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 4668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeFunction(edi, 4669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch actual, 4670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch JUMP_FUNCTION, 4671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch NullCallWrapper(), 4672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CALL_AS_FUNCTION); 467380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 467480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case: Non-function called. 467580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 46763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (RecordCallTarget()) { 46773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // If there is a call target cache, mark it megamorphic in the 46783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // non-function case. MegamorphicSentinel is an immortal immovable 46793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // object (undefined) so no write barrier is needed. 46803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), 46813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate))); 46823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 4683589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // Check for function proxy. 4684589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); 4685589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ j(not_equal, &non_function); 4686589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ pop(ecx); 4687589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ push(edi); // put proxy as additional argument under return address 4688589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ push(ecx); 4689589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ Set(eax, Immediate(argc_ + 1)); 4690589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ Set(ebx, Immediate(0)); 4691589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ SetCallKind(ecx, CALL_AS_FUNCTION); 4692589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); 4693589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch { 46943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline(); 4695589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ jmp(adaptor, RelocInfo::CODE_TARGET); 4696589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch } 4697589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 469880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // CALL_NON_FUNCTION expects the non-function callee as receiver (instead 469980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // of the original receiver from the call site). 4700589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ bind(&non_function); 470180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi); 470280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(argc_)); 470380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(ebx, Immediate(0)); 4704589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ SetCallKind(ecx, CALL_AS_METHOD); 470580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); 47063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline(); 470785b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch __ jmp(adaptor, RelocInfo::CODE_TARGET); 47085d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch} 47095d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch 47105d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch 47113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CallConstructStub::Generate(MacroAssembler* masm) { 47123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // eax : number of arguments 47133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ebx : cache cell for call target 47143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // edi : constructor function 47153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label slow, non_function_call; 47163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 47173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Check that function is not a smi. 47183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfSmi(edi, &non_function_call); 47193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Check that function is a JSFunction. 47203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 47213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &slow); 47223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 47233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (RecordCallTarget()) { 47243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateRecordCallTarget(masm); 47253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 47263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 47273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Jump to the function-specific construct stub. 47283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 47293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset)); 47303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); 47313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(ebx); 47323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 47333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // edi: called object 47343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // eax: number of arguments 47353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ecx: object map 47363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label do_call; 47373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&slow); 47383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); 47393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &non_function_call); 47403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR); 47413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&do_call); 47423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 47433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&non_function_call); 47443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); 47453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&do_call); 47463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set expected number of arguments to zero (not changing eax). 47473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Set(ebx, Immediate(0)); 47483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Handle<Code> arguments_adaptor = 47493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); 47503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ SetCallKind(ecx, CALL_AS_METHOD); 47513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(arguments_adaptor, RelocInfo::CODE_TARGET); 47523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 47533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 47543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 475544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool CEntryStub::NeedsImmovableCode() { 475644f0eee88ff00398ff7f715fab053374d808c90dSteve Block return false; 475744f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 475844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 475944f0eee88ff00398ff7f715fab053374d808c90dSteve Block 47603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool CEntryStub::IsPregenerated() { 47613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return (!save_doubles_ || ISOLATE->fp_stubs_generated()) && 47623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch result_size_ == 1; 47633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 47643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 47653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 47663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CodeStub::GenerateStubsAheadOfTime() { 47673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CEntryStub::GenerateAheadOfTime(); 47683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(); 47693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // It is important that the store buffer overflow stubs are generated first. 47703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch RecordWriteStub::GenerateFixedRegStubsAheadOfTime(); 47713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 47723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 47733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 47743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CodeStub::GenerateFPStubs() { 47753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CEntryStub save_doubles(1, kSaveFPRegs); 47763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Handle<Code> code = save_doubles.GetCode(); 47773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch code->set_is_pregenerated(true); 47783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch code->GetIsolate()->set_fp_stubs_generated(true); 47793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 47803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 47813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 47823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CEntryStub::GenerateAheadOfTime() { 47833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CEntryStub stub(1, kDontSaveFPRegs); 47843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Handle<Code> code = stub.GetCode(); 47853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch code->set_is_pregenerated(true); 4786592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch} 4787592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch 4788592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch 478980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateCore(MacroAssembler* masm, 479080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_normal_exception, 479180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_termination_exception, 479280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_out_of_memory_exception, 479380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool do_gc, 47941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block bool always_allocate_scope) { 479580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result parameter for PerformGC, if any 479680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: pointer to C function (C callee-saved) 479780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebp: frame pointer (restored after C call) 479880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp: stack pointer (restored after C call) 479980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: number of arguments including receiver (C callee-saved) 480080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: pointer to the first argument (C callee-saved) 480180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 480280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result returned in eax, or eax+edx if result_size_ is 2. 480380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 480480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check stack alignment. 480580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 480680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CheckStackAlignment(); 480780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 480880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 480980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (do_gc) { 481080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Pass failure code returned from last attempt as first argument to 481180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the 481280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stack alignment is known to be correct. This function takes one argument 481380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // which is passed on the stack, and we know that the stack has been 481480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // prepared to pass at least one argument. 481580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 0 * kPointerSize), eax); // Result. 481680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY); 481780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 481880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 481980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference scope_depth = 482044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::heap_always_allocate_scope_depth(masm->isolate()); 482180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (always_allocate_scope) { 482280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ inc(Operand::StaticVariable(scope_depth)); 482380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 482480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 482580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call C function. 482680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 0 * kPointerSize), edi); // argc. 482780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand(esp, 1 * kPointerSize), esi); // argv. 482844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(Operand(esp, 2 * kPointerSize), 482944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Immediate(ExternalReference::isolate_address())); 48303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ call(ebx); 483180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is in eax or edx:eax - do not destroy these registers! 483280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 483380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (always_allocate_scope) { 483480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ dec(Operand::StaticVariable(scope_depth)); 483580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 483680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 483780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure we're not trying to return 'the hole' from the runtime 483880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // call as this may lead to crashes in the IC code later. 483980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 4840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label okay; 484144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, masm->isolate()->factory()->the_hole_value()); 4842257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &okay, Label::kNear); 484380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ int3(); 484480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&okay); 484580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 484680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 484780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for failure result. 484880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label failure_returned; 484980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); 485080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(ecx, Operand(eax, 1)); 485180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Lower 2 bits of ecx are 0 iff eax has failure tag. 485280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Immediate(kFailureTagMask)); 4853257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &failure_returned); 485480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 485544f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference pending_exception_address( 4856589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Isolate::kPendingExceptionAddress, masm->isolate()); 48571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 48581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check that there is no pending exception, otherwise we 48591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // should have returned some failure value. 48601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (FLAG_debug_code) { 48611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(edx); 48623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value())); 4863257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label okay; 48641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ cmp(edx, Operand::StaticVariable(pending_exception_address)); 48651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Cannot use check here as it attempts to generate call into runtime. 4866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &okay, Label::kNear); 48671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ int3(); 48681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&okay); 48691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ pop(edx); 48701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 48711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 487280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Exit the JavaScript to C++ exit frame. 48733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ LeaveExitFrame(save_doubles_ == kSaveFPRegs); 487480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 487580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 487680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handling of failure. 487780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&failure_returned); 487880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 487980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label retry; 488080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the returned exception is RETRY_AFTER_GC continue at retry label 488180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); 488280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); 488369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &retry, Label::kNear); 488480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 488580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Special handling of out of memory exceptions. 488680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException())); 488780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, throw_out_of_memory_exception); 488880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 488980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Retrieve the pending exception and clear the variable. 489080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand::StaticVariable(pending_exception_address)); 48913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value())); 489280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(pending_exception_address), edx); 489380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 489480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Special handling of termination exceptions which are uncatchable 489580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // by javascript code. 489644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(eax, masm->isolate()->factory()->termination_exception()); 489780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, throw_termination_exception); 489880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 489980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle normal exception. 490080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(throw_normal_exception); 490180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 490280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Retry. 490380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&retry); 490480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 490580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 490680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 490780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::Generate(MacroAssembler* masm) { 490880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: number of arguments including receiver 490980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: pointer to C function (C callee-saved) 491080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebp: frame pointer (restored after C call) 491180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp: stack pointer (restored after C call) 491280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: current context (C callee-saved) 491380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: JS function of the caller (C callee-saved) 491480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 491580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NOTE: Invocations of builtins may return failure objects instead 491680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // of a proper result. The builtin entry handles this by performing 491780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // a garbage collection and retrying the builtin (twice). 491880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 491980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Enter the exit frame that transitions from JavaScript to C++. 49203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ EnterExitFrame(save_doubles_ == kSaveFPRegs); 492180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 492280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result parameter for PerformGC, if any (setup below) 492380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: pointer to builtin function (C callee-saved) 492480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebp: frame pointer (restored after C call) 492580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp: stack pointer (restored after C call) 492680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: number of arguments including receiver (C callee-saved) 492780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: argv pointer (C callee-saved) 492880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 492980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_normal_exception; 493080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_termination_exception; 493180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_out_of_memory_exception; 493280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 493380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call into the runtime system. 493480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 493580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 493680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 493780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 493880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen false, 493980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen false); 494080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 494180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do space-specific GC and retry runtime call. 494280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 494380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 494480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 494580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 494680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen true, 494780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen false); 494880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 494980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do full GC and retry runtime call one final time. 495080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Failure* failure = Failure::InternalError(); 495180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure))); 495280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 495380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 495480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 495580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 495680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen true, 495780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen true); 495880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 495980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_out_of_memory_exception); 49603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set external caught exception to false. 49613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Isolate* isolate = masm->isolate(); 49623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress, 49633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch isolate); 49643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(Operand::StaticVariable(external_caught), Immediate(false)); 49653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 49663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set pending exception and eax to out of memory exception. 49673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference pending_exception(Isolate::kPendingExceptionAddress, 49683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch isolate); 49693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException())); 49703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(Operand::StaticVariable(pending_exception), eax); 49713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Fall through to the next label. 497280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 497380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_termination_exception); 49743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ThrowUncatchable(eax); 497580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 497680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_normal_exception); 49773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Throw(eax); 497880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 497980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 498080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 498180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { 49823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label invoke, handler_entry, exit; 498380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label not_outermost_js, not_outermost_js_2; 498480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 49853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up frame. 498680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ebp); 49873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebp, esp); 498880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 498980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Push marker in two places. 499080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; 499180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Immediate(Smi::FromInt(marker))); // context slot 499280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Immediate(Smi::FromInt(marker))); // function slot 499380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Save callee-saved registers (C calling conventions). 499480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(edi); 499580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(esi); 499680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ebx); 499780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 499880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Save copies of the top frame descriptor on the stack. 4999589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, masm->isolate()); 500080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Operand::StaticVariable(c_entry_fp)); 500180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 500280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If this is the outermost JS call, set js_entry_sp value. 5003589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, 500444f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 500580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0)); 500669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_equal, ¬_outermost_js, Label::kNear); 500780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(js_entry_sp), ebp); 5008053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); 5009053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block Label cont; 501069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&cont, Label::kNear); 501180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_outermost_js); 5012053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME))); 5013053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ bind(&cont); 501480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 50153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Jump to a faked try block that does the invoke, with a faked catch 50163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // block that sets the pending exception. 50173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&invoke); 50183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&handler_entry); 50193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch handler_offset_ = handler_entry.pos(); 50203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Caught exception: Store result (exception) in the pending exception 50213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // field in the JSEnv and return a failure sentinel. 5022589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch ExternalReference pending_exception(Isolate::kPendingExceptionAddress, 502344f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 502480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(pending_exception), eax); 502580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception())); 502680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&exit); 502780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 50283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Invoke: Link this frame into the handler chain. There's only one 50293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // handler block in this code object, so its index is 0. 503080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&invoke); 50313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ PushTryHandler(StackHandler::JS_ENTRY, 0); 503280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 503380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Clear any pending exceptions. 50343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value())); 503580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(pending_exception), edx); 503680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 503780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fake a receiver (NULL). 503880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(Immediate(0)); // receiver 503980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 50403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Invoke the function by calling through JS entry trampoline builtin and 50413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // pop the faked function when we return. Notice that we cannot store a 50423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // reference to the trampoline code directly in this stub, because the 50433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // builtin stubs may not have been generated yet. 504480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (is_construct) { 50453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline, 50463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm->isolate()); 504780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Immediate(construct_entry)); 504880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 504944f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference entry(Builtins::kJSEntryTrampoline, 505044f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 505180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Immediate(entry)); 505280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 505380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(edx, 0)); // deref address 505480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); 50553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ call(edx); 505680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 505780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Unlink this frame from the handler chain. 5058053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ PopTryHandler(); 505980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5060053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ bind(&exit); 5061053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block // Check if the current stack frame is marked as the outermost JS frame. 5062053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ pop(ebx); 50633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ebx, Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); 506480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, ¬_outermost_js_2); 506580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0)); 506680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_outermost_js_2); 506780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 506880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore the top frame descriptor from the stack. 506944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ pop(Operand::StaticVariable(ExternalReference( 5070589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Isolate::kCEntryFPAddress, 507144f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()))); 507280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 507380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore callee-saved registers (C calling conventions). 507480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ebx); 507580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(esi); 507680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(edi); 50773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(esp, Immediate(2 * kPointerSize)); // remove markers 507880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 507980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore frame pointer and return. 508080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ebp); 508180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 508280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 508380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 508480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5085086aeeaae12517475c22695a200be45495516549Ben Murdoch// Generate stub code for instanceof. 5086086aeeaae12517475c22695a200be45495516549Ben Murdoch// This code can patch a call site inlined cache of the instance of check, 5087086aeeaae12517475c22695a200be45495516549Ben Murdoch// which looks like this. 5088086aeeaae12517475c22695a200be45495516549Ben Murdoch// 5089086aeeaae12517475c22695a200be45495516549Ben Murdoch// 81 ff XX XX XX XX cmp edi, <the hole, patched to a map> 5090086aeeaae12517475c22695a200be45495516549Ben Murdoch// 75 0a jne <some near label> 5091086aeeaae12517475c22695a200be45495516549Ben Murdoch// b8 XX XX XX XX mov eax, <the hole, patched to either true or false> 5092086aeeaae12517475c22695a200be45495516549Ben Murdoch// 5093086aeeaae12517475c22695a200be45495516549Ben Murdoch// If call site patching is requested the stack will have the delta from the 5094086aeeaae12517475c22695a200be45495516549Ben Murdoch// return address to the cmp instruction just below the return address. This 5095086aeeaae12517475c22695a200be45495516549Ben Murdoch// also means that call site patching can only take place with arguments in 5096086aeeaae12517475c22695a200be45495516549Ben Murdoch// registers. TOS looks like this when call site patching is requested 5097086aeeaae12517475c22695a200be45495516549Ben Murdoch// 5098086aeeaae12517475c22695a200be45495516549Ben Murdoch// esp[0] : return address 5099086aeeaae12517475c22695a200be45495516549Ben Murdoch// esp[4] : delta from return address to cmp instruction 5100086aeeaae12517475c22695a200be45495516549Ben Murdoch// 510180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid InstanceofStub::Generate(MacroAssembler* masm) { 5102086aeeaae12517475c22695a200be45495516549Ben Murdoch // Call site inlining and patching implies arguments in registers. 5103086aeeaae12517475c22695a200be45495516549Ben Murdoch ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck()); 5104086aeeaae12517475c22695a200be45495516549Ben Murdoch 5105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fixed register usage throughout the stub. 5106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register object = eax; // Object (lhs). 5107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register map = ebx; // Map of the object. 5108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register function = edx; // Function (rhs). 5109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register prototype = edi; // Prototype of the function. 5110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Register scratch = ecx; 5111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5112086aeeaae12517475c22695a200be45495516549Ben Murdoch // Constants describing the call site code to patch. 5113086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int kDeltaToCmpImmediate = 2; 5114086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int kDeltaToMov = 8; 5115086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int kDeltaToMovImmediate = 9; 51163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch static const int8_t kCmpEdiOperandByte1 = BitCast<int8_t, uint8_t>(0x3b); 51173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch static const int8_t kCmpEdiOperandByte2 = BitCast<int8_t, uint8_t>(0x3d); 5118086aeeaae12517475c22695a200be45495516549Ben Murdoch static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8); 5119086aeeaae12517475c22695a200be45495516549Ben Murdoch 51203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference roots_array_start = 51213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference::roots_array_start(masm->isolate()); 5122086aeeaae12517475c22695a200be45495516549Ben Murdoch 5123086aeeaae12517475c22695a200be45495516549Ben Murdoch ASSERT_EQ(object.code(), InstanceofStub::left().code()); 5124086aeeaae12517475c22695a200be45495516549Ben Murdoch ASSERT_EQ(function.code(), InstanceofStub::right().code()); 5125086aeeaae12517475c22695a200be45495516549Ben Murdoch 5126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Get the object and function - they are always both needed. 5127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label slow, not_js_object; 5128086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasArgsInRegisters()) { 5129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(object, Operand(esp, 2 * kPointerSize)); 5130b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(function, Operand(esp, 1 * kPointerSize)); 5131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 513280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 513380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the left hand is a JS object. 51343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(object, ¬_js_object); 5135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); 513680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5137086aeeaae12517475c22695a200be45495516549Ben Murdoch // If there is a call site cache don't look in the global cache, but do the 5138086aeeaae12517475c22695a200be45495516549Ben Murdoch // real lookup and update the call site cache. 5139086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasCallSiteInlineCheck()) { 5140086aeeaae12517475c22695a200be45495516549Ben Murdoch // Look up the function and the map in the instanceof cache. 5141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 5142086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); 51433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(function, Operand::StaticArray(scratch, 51443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch times_pointer_size, 51453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch roots_array_start)); 5146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 5147086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); 5148086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmp(map, Operand::StaticArray( 51493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch scratch, times_pointer_size, roots_array_start)); 5150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 5151086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); 5152086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(eax, Operand::StaticArray( 51533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch scratch, times_pointer_size, roots_array_start)); 5154086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 5155086aeeaae12517475c22695a200be45495516549Ben Murdoch __ bind(&miss); 5156086aeeaae12517475c22695a200be45495516549Ben Murdoch } 5157086aeeaae12517475c22695a200be45495516549Ben Murdoch 5158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Get the prototype of the function. 51593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true); 516080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 516180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the function prototype is a JS object. 51623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(prototype, &slow); 5163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); 5164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5165086aeeaae12517475c22695a200be45495516549Ben Murdoch // Update the global instanceof or call site inlined cache with the current 5166086aeeaae12517475c22695a200be45495516549Ben Murdoch // map and function. The cached answer will be set when it is known below. 5167086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasCallSiteInlineCheck()) { 5168b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); 51693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start), 51703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch map); 5171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); 51723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start), 5173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch function); 5174086aeeaae12517475c22695a200be45495516549Ben Murdoch } else { 5175086aeeaae12517475c22695a200be45495516549Ben Murdoch // The constants for the code patching are based on no push instructions 5176086aeeaae12517475c22695a200be45495516549Ben Murdoch // at the call site. 5177086aeeaae12517475c22695a200be45495516549Ben Murdoch ASSERT(HasArgsInRegisters()); 5178086aeeaae12517475c22695a200be45495516549Ben Murdoch // Get return address and delta to inlined map check. 5179086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Operand(esp, 0 * kPointerSize)); 5180086aeeaae12517475c22695a200be45495516549Ben Murdoch __ sub(scratch, Operand(esp, 1 * kPointerSize)); 5181086aeeaae12517475c22695a200be45495516549Ben Murdoch if (FLAG_debug_code) { 51823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmpb(Operand(scratch, 0), kCmpEdiOperandByte1); 5183086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 1)"); 51843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmpb(Operand(scratch, 1), kCmpEdiOperandByte2); 5185086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 2)"); 5186086aeeaae12517475c22695a200be45495516549Ben Murdoch } 51873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(scratch, Operand(scratch, kDeltaToCmpImmediate)); 51883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(Operand(scratch, 0), map); 5189086aeeaae12517475c22695a200be45495516549Ben Murdoch } 5190b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5191b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Loop through the prototype chain of the object looking for the function 5192b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // prototype. 5193b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset)); 5194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop, is_instance, is_not_instance; 519580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 51963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(scratch, prototype); 5197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &is_instance, Label::kNear); 519844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 51993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(scratch, Immediate(factory->null_value())); 5200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &is_not_instance, Label::kNear); 5201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); 5202b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); 520380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&loop); 520480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 520580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&is_instance); 5206086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasCallSiteInlineCheck()) { 5207086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Set(eax, Immediate(0)); 5208086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); 5209086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(Operand::StaticArray(scratch, 52103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch times_pointer_size, roots_array_start), eax); 5211086aeeaae12517475c22695a200be45495516549Ben Murdoch } else { 5212086aeeaae12517475c22695a200be45495516549Ben Murdoch // Get return address and delta to inlined map check. 521344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, factory->true_value()); 5214086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Operand(esp, 0 * kPointerSize)); 5215086aeeaae12517475c22695a200be45495516549Ben Murdoch __ sub(scratch, Operand(esp, 1 * kPointerSize)); 5216086aeeaae12517475c22695a200be45495516549Ben Murdoch if (FLAG_debug_code) { 5217086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); 5218086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); 5219086aeeaae12517475c22695a200be45495516549Ben Murdoch } 5220086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(Operand(scratch, kDeltaToMovImmediate), eax); 5221086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!ReturnTrueFalseObject()) { 5222086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Set(eax, Immediate(0)); 5223086aeeaae12517475c22695a200be45495516549Ben Murdoch } 5224086aeeaae12517475c22695a200be45495516549Ben Murdoch } 5225086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 522680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 522780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&is_not_instance); 5228086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasCallSiteInlineCheck()) { 5229086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 5230086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); 5231086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(Operand::StaticArray( 52323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch scratch, times_pointer_size, roots_array_start), eax); 5233086aeeaae12517475c22695a200be45495516549Ben Murdoch } else { 5234086aeeaae12517475c22695a200be45495516549Ben Murdoch // Get return address and delta to inlined map check. 523544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, factory->false_value()); 5236086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(scratch, Operand(esp, 0 * kPointerSize)); 5237086aeeaae12517475c22695a200be45495516549Ben Murdoch __ sub(scratch, Operand(esp, 1 * kPointerSize)); 5238086aeeaae12517475c22695a200be45495516549Ben Murdoch if (FLAG_debug_code) { 5239086aeeaae12517475c22695a200be45495516549Ben Murdoch __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); 5240086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); 5241086aeeaae12517475c22695a200be45495516549Ben Murdoch } 5242086aeeaae12517475c22695a200be45495516549Ben Murdoch __ mov(Operand(scratch, kDeltaToMovImmediate), eax); 5243086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!ReturnTrueFalseObject()) { 5244086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 5245086aeeaae12517475c22695a200be45495516549Ben Murdoch } 5246086aeeaae12517475c22695a200be45495516549Ben Murdoch } 5247086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 5248b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5249b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label object_not_null, object_not_null_or_smi; 5250b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_js_object); 5251b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Before null, smi and string value checks, check that the rhs is a function 5252b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // as for a non-function rhs an exception needs to be thrown. 525369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfSmi(function, &slow, Label::kNear); 5254b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); 525569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_equal, &slow, Label::kNear); 5256b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Null is not instance of anything. 525844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(object, factory->null_value()); 525969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(not_equal, &object_not_null, Label::kNear); 5260b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 5261086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 5262b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&object_not_null); 5264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Smi values is not instance of anything. 526569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfNotSmi(object, &object_not_null_or_smi, Label::kNear); 5266b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 5267086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 5268b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5269b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&object_not_null_or_smi); 5270b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // String values is not instance of anything. 5271b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Condition is_string = masm->IsObjectStringType(object, scratch, scratch); 527269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(NegateCondition(is_string), &slow, Label::kNear); 5273b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(1))); 5274086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 527580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 527680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case: Go through the JavaScript implementation. 527780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 5278086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!ReturnTrueFalseObject()) { 5279086aeeaae12517475c22695a200be45495516549Ben Murdoch // Tail call the builtin which returns 0 or 1. 5280086aeeaae12517475c22695a200be45495516549Ben Murdoch if (HasArgsInRegisters()) { 5281086aeeaae12517475c22695a200be45495516549Ben Murdoch // Push arguments below return address. 5282086aeeaae12517475c22695a200be45495516549Ben Murdoch __ pop(scratch); 5283086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(object); 5284086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(function); 5285086aeeaae12517475c22695a200be45495516549Ben Murdoch __ push(scratch); 5286086aeeaae12517475c22695a200be45495516549Ben Murdoch } 5287086aeeaae12517475c22695a200be45495516549Ben Murdoch __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 5288086aeeaae12517475c22695a200be45495516549Ben Murdoch } else { 5289086aeeaae12517475c22695a200be45495516549Ben Murdoch // Call the builtin and convert 0/1 to true/false. 52903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 52913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FrameScope scope(masm, StackFrame::INTERNAL); 52923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(object); 52933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(function); 52943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); 52953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 5296257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label true_value, done; 52973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(eax, eax); 5298257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &true_value, Label::kNear); 529944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, factory->false_value()); 5300257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&done, Label::kNear); 5301086aeeaae12517475c22695a200be45495516549Ben Murdoch __ bind(&true_value); 530244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(eax, factory->true_value()); 5303086aeeaae12517475c22695a200be45495516549Ben Murdoch __ bind(&done); 5304086aeeaae12517475c22695a200be45495516549Ben Murdoch __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 5305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 530680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 530780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 530880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5309086aeeaae12517475c22695a200be45495516549Ben MurdochRegister InstanceofStub::left() { return eax; } 5310086aeeaae12517475c22695a200be45495516549Ben Murdoch 5311086aeeaae12517475c22695a200be45495516549Ben Murdoch 5312086aeeaae12517475c22695a200be45495516549Ben MurdochRegister InstanceofStub::right() { return edx; } 5313086aeeaae12517475c22695a200be45495516549Ben Murdoch 5314086aeeaae12517475c22695a200be45495516549Ben Murdoch 531580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenint CompareStub::MinorKey() { 531680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Encode the three parameters in a unique 16 bit value. To avoid duplicate 531780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stubs the never NaN NaN condition is only taken into account if the 531880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // condition is equals. 531980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(static_cast<unsigned>(cc_) < (1 << 12)); 532080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 532180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return ConditionField::encode(static_cast<unsigned>(cc_)) 532280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | RegisterField::encode(false) // lhs_ and rhs_ are not used 532380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | StrictField::encode(strict_) 532480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) 53250d5e116f6aee03185f237311a943491bb079a768Kristian Monsen | IncludeNumberCompareField::encode(include_number_compare_) 53260d5e116f6aee03185f237311a943491bb079a768Kristian Monsen | IncludeSmiCompareField::encode(include_smi_compare_); 532780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 532880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 532980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 533080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Unfortunately you have to run without snapshots to see most of these 533180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// names in the profile since most compare stubs end up in the snapshot. 53323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid CompareStub::PrintName(StringStream* stream) { 533380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 533480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const char* cc_name; 533580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen switch (cc_) { 533680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case less: cc_name = "LT"; break; 533780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case greater: cc_name = "GT"; break; 533880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case less_equal: cc_name = "LE"; break; 533980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case greater_equal: cc_name = "GE"; break; 534080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case equal: cc_name = "EQ"; break; 534180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case not_equal: cc_name = "NE"; break; 534280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen default: cc_name = "UnknownCondition"; break; 534380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 53443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch bool is_equality = cc_ == equal || cc_ == not_equal; 53453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("CompareStub_%s", cc_name); 53463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (strict_ && is_equality) stream->Add("_STRICT"); 53473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN"); 53483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (!include_number_compare_) stream->Add("_NO_NUMBER"); 53493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (!include_smi_compare_) stream->Add("_NO_SMI"); 535080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 535180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 535280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 535380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// ------------------------------------------------------------------------- 535480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharCodeAtGenerator 535580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 535680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { 535780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the receiver is a smi trigger the non-string case. 535880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 53593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(object_, receiver_not_string_); 536080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 536180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fetch the instance type of the receiver into result register. 536280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); 536380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); 536480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the receiver is not a string trigger the non-string case. 536580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(result_, Immediate(kIsNotStringMask)); 536680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, receiver_not_string_); 536780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 536880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the index is non-smi trigger the non-smi case. 536980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 53703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(index_, &index_not_smi_); 537180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&got_smi_index_); 537280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 537380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for index out of range. 53743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(index_, FieldOperand(object_, String::kLengthOffset)); 537580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(above_equal, index_out_of_range_); 537680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 53773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ SmiUntag(index_); 537885b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch 53793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Factory* factory = masm->isolate()->factory(); 53803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch StringCharLoadGenerator::Generate( 53813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm, factory, object_, index_, result_, &call_runtime_); 538280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 538380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiTag(result_); 538480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&exit_); 538580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 538680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 538780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 538880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateSlow( 53893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler* masm, 53903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const RuntimeCallHelper& call_helper) { 539180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough to CharCodeAt slow case"); 539280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 539380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Index is not a smi. 539480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&index_not_smi_); 539580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If index is a heap number, try converting it to an integer. 539644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CheckMap(index_, 539744f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()->factory()->heap_number_map(), 539844f0eee88ff00398ff7f715fab053374d808c90dSteve Block index_not_number_, 5399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch DONT_DO_SMI_CHECK); 540080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 540180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(object_); 540280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(index_); // Consumed by runtime conversion function. 540380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (index_flags_ == STRING_INDEX_IS_NUMBER) { 540480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); 540580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 540680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); 540780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NumberToSmi discards numbers that are not exact integers. 540880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kNumberToSmi, 1); 540980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 54103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (!index_.is(eax)) { 541180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Save the conversion result before the pop instructions below 541280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // have a chance to overwrite it. 54133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(index_, eax); 541480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 541580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(object_); 541680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Reload the instance type. 541780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); 541880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); 541980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 542080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If index is still not a smi, it must be out of range. 542180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 54223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfNotSmi(index_, index_out_of_range_); 542380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Otherwise, return to the fast path. 542480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&got_smi_index_); 542580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 542680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call runtime. We get here when the receiver is a string and the 542780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // index is a number, but the code of getting the actual character 542880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // is too complex (e.g., when the string needs to be flattened). 542980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&call_runtime_); 543080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 543180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(object_); 54323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ SmiTag(index_); 543380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(index_); 543480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kStringCharCodeAt, 2); 543580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!result_.is(eax)) { 543680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, eax); 543780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 543880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 543980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&exit_); 544080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 544180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough from CharCodeAt slow case"); 544280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 544380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 544480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 544580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// ------------------------------------------------------------------------- 544680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharFromCodeGenerator 544780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 544880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { 544980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fast case of Heap::LookupSingleCharacterStringFromCode. 545080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 545180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiShiftSize == 0); 545280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); 545380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(code_, 545480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(kSmiTagMask | 545580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ((~String::kMaxAsciiCharCode) << kSmiTagSize))); 5456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &slow_case_); 545780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 545844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 545944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Set(result_, Immediate(factory->single_character_string_cache())); 546080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 546180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize == 1); 546280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiShiftSize == 0); 54633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // At this point code register contains smi tagged ASCII char code. 546480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, FieldOperand(result_, 546580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen code_, times_half_pointer_size, 546680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FixedArray::kHeaderSize)); 546744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(result_, factory->undefined_value()); 5468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &slow_case_); 546980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&exit_); 547080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 547180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 547280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 547380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateSlow( 54743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler* masm, 54753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const RuntimeCallHelper& call_helper) { 547680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough to CharFromCode slow case"); 547780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 547880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow_case_); 547980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 548080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(code_); 548180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kCharFromCode, 1); 548280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!result_.is(eax)) { 548380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, eax); 548480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 548580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 548680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&exit_); 548780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 548880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough from CharFromCode slow case"); 548980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 549080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 549180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 549280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// ------------------------------------------------------------------------- 549380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharAtGenerator 549480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 549580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateFast(MacroAssembler* masm) { 549680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_code_at_generator_.GenerateFast(masm); 549780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_from_code_generator_.GenerateFast(masm); 549880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 549980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 550080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 550180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateSlow( 55023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler* masm, 55033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const RuntimeCallHelper& call_helper) { 550480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_code_at_generator_.GenerateSlow(masm, call_helper); 550580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_from_code_generator_.GenerateSlow(masm, call_helper); 550680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 550780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 550880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 550980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringAddStub::Generate(MacroAssembler* masm) { 55103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label call_runtime, call_builtin; 55119ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Builtins::JavaScript builtin_id = Builtins::ADD; 551280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 551380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the two arguments. 551480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. 551580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. 551680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 551780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure that both arguments are strings if not known in advance. 55189ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick if (flags_ == NO_STRING_ADD_FLAGS) { 55193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfSmi(eax, &call_runtime); 552080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx); 55213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(above_equal, &call_runtime); 552280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 552380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // First argument is a a string, test second. 55243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfSmi(edx, &call_runtime); 552580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); 55263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(above_equal, &call_runtime); 55279ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick } else { 55289ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Here at least one of the arguments is definitely a string. 55299ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // We convert the one that is not known to be a string. 55309ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { 55319ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); 55329ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi, 55339ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick &call_builtin); 55349ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick builtin_id = Builtins::STRING_ADD_RIGHT; 55359ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { 55369ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); 55379ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick GenerateConvertArgument(masm, 1 * kPointerSize, edx, ebx, ecx, edi, 55389ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick &call_builtin); 55399ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick builtin_id = Builtins::STRING_ADD_LEFT; 55409ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick } 554180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 554280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 554380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both arguments are strings. 554480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first string 554580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: second string 554680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if either of the strings are empty. In that case return the other. 5547257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label second_not_zero_length, both_not_zero_length; 554880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); 554980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 55503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(ecx, ecx); 5551257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &second_not_zero_length, Label::kNear); 555280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Second string is empty, result is first string which is already in eax. 555344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 555444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 555580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 555680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&second_not_zero_length); 555780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); 555880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 55593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(ebx, ebx); 5560257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &both_not_zero_length, Label::kNear); 556180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // First string is empty, result is second string which is in edx. 556280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, edx); 556344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 556480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 556580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 556680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both strings are non-empty. 556780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first string 556880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: length of first string as a smi 556980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: length of second string as a smi 557080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: second string 557180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Look at the length of the result of adding the two strings. 557280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label string_add_flat_result, longer_than_two; 557380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&both_not_zero_length); 55743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(ebx, ecx); 557580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength); 557680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle exceptionally long strings in the runtime system. 55773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(overflow, &call_runtime); 557844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Use the symbol table when adding two one character strings, as it 557944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // helps later optimizations to return a symbol here. 55803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ebx, Immediate(Smi::FromInt(2))); 558180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &longer_than_two); 558280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 55833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Check that both strings are non-external ASCII strings. 55843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, &call_runtime); 558580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 55869ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Get the two characters forming the new string. 558780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); 558880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); 558980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 559080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try to lookup two character string in symbol table. If it is not found 559180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // just allocate a new one. 55929ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label make_two_character_string, make_two_character_string_no_reload; 559380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateTwoCharacterSymbolTableProbe( 55949ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick masm, ebx, ecx, eax, edx, edi, 55959ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick &make_two_character_string_no_reload, &make_two_character_string); 559644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 559780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 559880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 55999ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Allocate a two character string. 560080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&make_two_character_string); 56019ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Reload the arguments. 56029ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. 56039ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. 56049ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Get the two characters forming the new string. 56059ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); 56069ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); 56079ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(&make_two_character_string_no_reload); 560844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_make_two_char(), 1); 56093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateAsciiString(eax, 2, edi, edx, &call_runtime); 56109ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Pack both characters in ebx. 56119ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ shl(ecx, kBitsPerByte); 56123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ or_(ebx, ecx); 56139ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Set the characters in the new string. 56149ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx); 561544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 56169ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ ret(2 * kPointerSize); 561780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 561880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&longer_than_two); 561980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if resulting string will be flat. 56203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ebx, Immediate(Smi::FromInt(ConsString::kMinLength))); 562180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(below, &string_add_flat_result); 562280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 562380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If result is not supposed to be flat allocate a cons string object. If both 56243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // strings are ASCII the result is an ASCII cons string. 562580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_ascii, allocated, ascii_data; 562680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); 562780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); 562880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 562980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); 56303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(ecx, edi); 5631589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 5632589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 5633589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ test(ecx, Immediate(kStringEncodingMask)); 563480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &non_ascii); 563580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&ascii_data); 56363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Allocate an ASCII cons string. 56373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateAsciiConsString(ecx, edi, no_reg, &call_runtime); 563880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&allocated); 563980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fill the fields of the cons string. 564080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) __ AbortIfNotSmi(ebx); 564180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); 564280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), 564380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(String::kEmptyHashField)); 564480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); 564580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); 564680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, ecx); 564744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 564880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 564980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_ascii); 565080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // At least one of the strings is two-byte. Check whether it happens 56513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // to contain only ASCII characters. 565280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: first instance type AND second instance type. 565380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: second instance type. 565480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(ecx, Immediate(kAsciiDataHintMask)); 565580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &ascii_data); 565680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 565780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 56583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(edi, ecx); 565980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); 566080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(edi, kAsciiStringTag | kAsciiDataHintTag); 566180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); 566280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &ascii_data); 566380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate a two byte cons string. 56643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateTwoByteConsString(ecx, edi, no_reg, &call_runtime); 566580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&allocated); 566680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 56673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // We cannot encounter sliced strings or cons strings here since: 56683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength); 56693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Handle creating a flat result from either external or sequential strings. 56703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Locate the first characters' locations. 567180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first string 567280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: length of resulting flat string as a smi 567380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: second string 56743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label first_prepared, second_prepared; 56753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label first_is_sequential, second_is_sequential; 567680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&string_add_flat_result); 567780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 567880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 56793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ecx: instance type of first string 56803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kSeqStringTag == 0); 56813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test_b(ecx, kStringRepresentationMask); 56823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(zero, &first_is_sequential, Label::kNear); 56833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Rule out short external string and load string resource. 56843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kShortExternalStringTag != 0); 56853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test_b(ecx, kShortExternalStringMask); 56863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_zero, &call_runtime); 56873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset)); 56883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); 56893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&first_prepared, Label::kNear); 56903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&first_is_sequential); 56913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(eax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 56923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&first_prepared); 56933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 56943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 56953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); 56963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Check whether both strings have same encoding. 56973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // edi: instance type of second string 56983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(ecx, edi); 56993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test_b(ecx, kStringEncodingMask); 57003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_zero, &call_runtime); 57013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kSeqStringTag == 0); 57023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test_b(edi, kStringRepresentationMask); 57033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(zero, &second_is_sequential, Label::kNear); 57043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Rule out short external string and load string resource. 57053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kShortExternalStringTag != 0); 57063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test_b(edi, kShortExternalStringMask); 57073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_zero, &call_runtime); 57083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edx, FieldOperand(edx, ExternalString::kResourceDataOffset)); 57093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); 57103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&second_prepared, Label::kNear); 57113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&second_is_sequential); 57123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 57133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&second_prepared); 57143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 57153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Push the addresses of both strings' first characters onto the stack. 57163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(edx); 57173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(eax); 57183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 57193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label non_ascii_string_add_flat_result, call_runtime_drop_two; 57203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // edi: instance type of second string 57213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // First string and second string have the same encoding. 57223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kTwoByteStringTag == 0); 57233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test_b(edi, kStringEncodingMask); 572480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &non_ascii_string_add_flat_result); 572580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 57263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Both strings are ASCII strings. 572780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: length of resulting flat string as a smi 572880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ebx); 57293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); 573080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 573180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, eax); 573280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 57333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(ecx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 57343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load first argument's length and first character location. Account for 57353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // values currently on the stack when fetching arguments from it. 57363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edx, Operand(esp, 4 * kPointerSize)); 573780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 573880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edi); 57393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(edx); 574080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 574180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: first character of result 574280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: first char of first argument 574380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: length of first argument 574480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); 57453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load second argument's length and first character location. Account for 57463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // values currently on the stack when fetching arguments from it. 57473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edx, Operand(esp, 2 * kPointerSize)); 574880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 574980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edi); 57503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(edx); 575180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 575280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: next character of result 575380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: first char of second argument 575480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: length of second argument 575580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); 575644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 575780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 575880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 575980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle creating a flat two byte result. 576080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: first string - known to be two byte 576180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: length of resulting flat string as a smi 576280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: second string 576380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_ascii_string_add_flat_result); 57643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Both strings are two byte strings. 576580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ebx); 57663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); 576780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 576880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, eax); 576980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 57703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(ecx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 57713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load second argument's length and first character location. Account for 57723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // values currently on the stack when fetching arguments from it. 57733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edx, Operand(esp, 4 * kPointerSize)); 577480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 577580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edi); 57763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(edx); 577780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 577880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: first character of result 577980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: first char of first argument 578080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: length of first argument 578180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); 57823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load second argument's length and first character location. Account for 57833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // values currently on the stack when fetching arguments from it. 57843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edx, Operand(esp, 2 * kPointerSize)); 578580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 578680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(edi); 57873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(edx); 578880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 578980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: next character of result 579080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: first char of second argument 579180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: length of second argument 579280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); 579344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1); 579480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 579580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 57963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Recover stack pointer before jumping to runtime. 57973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&call_runtime_drop_two); 57983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Drop(2); 579980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump to runtime to add the two strings. 58003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&call_runtime); 580180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kStringAdd, 2, 1); 58029ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 58039ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick if (call_builtin.is_linked()) { 58049ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(&call_builtin); 58059ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); 58069ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick } 58079ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick} 58089ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 58099ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 58109ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrickvoid StringAddStub::GenerateConvertArgument(MacroAssembler* masm, 58119ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick int stack_offset, 58129ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Register arg, 58139ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Register scratch1, 58149ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Register scratch2, 58159ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Register scratch3, 58169ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label* slow) { 58179ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // First check if the argument is already a string. 58189ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label not_string, done; 58193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(arg, ¬_string); 58209ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); 58219ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ j(below, &done); 58229ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 58239ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Check the number to string cache. 58249ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label not_cached; 58259ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(¬_string); 58269ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Puts the cached result into scratch1. 58279ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick NumberToStringStub::GenerateLookupNumberStringCache(masm, 58289ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick arg, 58299ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick scratch1, 58309ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick scratch2, 58319ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick scratch3, 58329ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick false, 58339ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick ¬_cached); 58349ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(arg, scratch1); 58359ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(Operand(esp, stack_offset), arg); 58369ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ jmp(&done); 58379ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 58389ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Check if the argument is a safe string wrapper. 58399ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(¬_cached); 58403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(arg, slow); 58419ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1); // map -> scratch1. 58429ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ j(not_equal, slow); 58439ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ test_b(FieldOperand(scratch1, Map::kBitField2Offset), 58449ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 1 << Map::kStringWrapperSafeForDefaultValueOf); 58459ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ j(zero, slow); 58469ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(arg, FieldOperand(arg, JSValue::kValueOffset)); 58479ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(Operand(esp, stack_offset), arg); 58489ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 58499ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ bind(&done); 585080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 585180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 585280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 585380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharacters(MacroAssembler* masm, 585480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register dest, 585580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register src, 585680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register count, 585780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch, 585880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool ascii) { 5859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop; 586080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 586180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // This loop just copies one character at a time, as it is only used for very 586280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // short strings. 586380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (ascii) { 586480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_b(scratch, Operand(src, 0)); 586580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_b(Operand(dest, 0), scratch); 58663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(src, Immediate(1)); 58673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(dest, Immediate(1)); 586880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 586980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_w(scratch, Operand(src, 0)); 587080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_w(Operand(dest, 0), scratch); 58713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(src, Immediate(2)); 58723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(dest, Immediate(2)); 587380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 58743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(count, Immediate(1)); 587580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &loop); 587680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 587780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 587880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 587980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, 588080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register dest, 588180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register src, 588280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register count, 588380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch, 588480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool ascii) { 588580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy characters using rep movs of doublewords. 588680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The destination is aligned on a 4 byte boundary because we are 588780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // copying to the beginning of a newly allocated string. 588880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(dest.is(edi)); // rep movs destination 588980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(src.is(esi)); // rep movs source 589080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(count.is(ecx)); // rep movs count 589180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(dest)); 589280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(src)); 589380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(!scratch.is(count)); 589480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 589580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Nothing to do for zero characters. 589680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label done; 58973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(count, count); 589880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &done); 589980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 590080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make count the number of bytes to copy. 590180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!ascii) { 590280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(count, 1); 590380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 590480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 590580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Don't enter the rep movs if there are less than 4 bytes to copy. 5906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label last_bytes; 590780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ test(count, Immediate(~3)); 5908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &last_bytes, Label::kNear); 590980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 591080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy from edi to esi using rep movs instruction. 591180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, count); 591280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sar(count, 2); // Number of doublewords to copy. 591380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cld(); 591480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ rep_movs(); 591580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 591680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find number of bytes left. 591780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(count, scratch); 591880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(count, 3); 591980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 592080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if there are more bytes to copy. 592180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&last_bytes); 59223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(count, count); 592380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(zero, &done); 592480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 592580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy remaining characters. 5926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop; 592780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 592880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_b(scratch, Operand(src, 0)); 592980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov_b(Operand(dest, 0), scratch); 59303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(src, Immediate(1)); 59313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(dest, Immediate(1)); 59323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(count, Immediate(1)); 593380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_zero, &loop); 593480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 593580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 593680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 593780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 593880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 593980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, 594080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register c1, 594180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register c2, 594280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 594380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 594480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch3, 59459ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Label* not_probed, 594680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_found) { 594780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Register scratch3 is the general scratch register in this function. 594880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch = scratch3; 594980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 595080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure that both characters are not digits as such strings has a 595180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // different hash algorithm. Don't try to look for these in the symbol table. 5952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_array_index; 595380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, c1); 59543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(scratch, Immediate(static_cast<int>('0'))); 59553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(scratch, Immediate(static_cast<int>('9' - '0'))); 5956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(above, ¬_array_index, Label::kNear); 595780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, c2); 59583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(scratch, Immediate(static_cast<int>('0'))); 59593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(scratch, Immediate(static_cast<int>('9' - '0'))); 59609ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ j(below_equal, not_probed); 596180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 596280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_array_index); 596380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate the two character string hash. 596480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash = scratch1; 596580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateHashInit(masm, hash, c1, scratch); 596680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateHashAddCharacter(masm, hash, c2, scratch); 596780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateHashGetHash(masm, hash, scratch); 596880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 596980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Collect the two characters in a register. 597080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register chars = c1; 597180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(c2, kBitsPerByte); 59723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ or_(chars, c2); 597380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 597480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 597580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash: hash of two character string. 597680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 597780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the symbol table. 597880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register symbol_table = c2; 59793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference roots_array_start = 59803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference::roots_array_start(masm->isolate()); 598180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex)); 598280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(symbol_table, 59833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Operand::StaticArray(scratch, times_pointer_size, roots_array_start)); 598480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 598580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate capacity mask from the symbol table capacity. 598680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register mask = scratch2; 598780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); 598880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(mask); 59893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(mask, Immediate(1)); 599080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 599180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Registers 599280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 599380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash: hash of two character string 599480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // symbol_table: symbol table 599580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // mask: capacity mask 599680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // scratch: - 599780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 599880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Perform a number of probes in the symbol table. 599980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen static const int kProbes = 4; 600080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label found_in_symbol_table; 600180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label next_probe[kProbes], next_probe_pop_mask[kProbes]; 6002692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch Register candidate = scratch; // Scratch register contains candidate. 600380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = 0; i < kProbes; i++) { 600480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate entry in symbol table. 600580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 600680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (i > 0) { 60073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(scratch, Immediate(SymbolTable::GetProbeOffset(i))); 600880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 60093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(scratch, mask); 601080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 601180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the entry from the symbol table. 601280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(SymbolTable::kEntrySize == 1); 601380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(candidate, 601480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldOperand(symbol_table, 601580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch, 601680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen times_pointer_size, 601780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SymbolTable::kElementsStartOffset)); 601880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 601980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If entry is undefined no string with this hash can be found. 602044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Factory* factory = masm->isolate()->factory(); 602144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(candidate, factory->undefined_value()); 602280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, not_found); 60233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(candidate, factory->the_hole_value()); 602444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ j(equal, &next_probe[i]); 602580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 602680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If length is not 2 the string is not a candidate. 602780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(FieldOperand(candidate, String::kLengthOffset), 602880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(Smi::FromInt(2))); 602980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(not_equal, &next_probe[i]); 603080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 603180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // As we are out of registers save the mask on the stack and use that 603280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // register as a temporary. 603380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(mask); 603480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register temp = mask; 603580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 60363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Check that the candidate is a non-external ASCII string. 603780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); 603880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); 603980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfInstanceTypeIsNotSequentialAscii( 604080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen temp, temp, &next_probe_pop_mask[i]); 604180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 604280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the two characters match. 604380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); 604480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(temp, 0x0000ffff); 60453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(chars, temp); 604680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(equal, &found_in_symbol_table); 604780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&next_probe_pop_mask[i]); 604880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(mask); 604980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&next_probe[i]); 605080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 605180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 605280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // No matching 2 character string found by probing. 605380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(not_found); 605480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 605580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Scratch register contains result when we fall through to here. 6056692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch Register result = candidate; 605780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&found_in_symbol_table); 605880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(mask); // Pop saved mask from the stack. 605980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!result.is(eax)) { 606080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, result); 606180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 606280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 606380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 606480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 606580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashInit(MacroAssembler* masm, 606680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 606780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register character, 606880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 6069c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch // hash = (seed + character) + ((seed + character) << 10); 6070c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch if (Serializer::enabled()) { 60713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference roots_array_start = 60723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference::roots_array_start(masm->isolate()); 6073c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ mov(scratch, Immediate(Heap::kHashSeedRootIndex)); 6074c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ mov(scratch, Operand::StaticArray(scratch, 6075c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch times_pointer_size, 60763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch roots_array_start)); 6077c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ SmiUntag(scratch); 60783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(scratch, character); 6079c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ mov(hash, scratch); 6080c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ shl(scratch, 10); 60813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(hash, scratch); 6082c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch } else { 6083c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch int32_t seed = masm->isolate()->heap()->HashSeed(); 6084c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ lea(scratch, Operand(character, seed)); 6085c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ shl(scratch, 10); 6086c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ lea(hash, Operand(scratch, character, times_1, seed)); 6087c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch } 608880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 6; 608980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 6090692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ shr(scratch, 6); 60913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(hash, scratch); 609280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 609380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 609480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 609580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, 609680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 609780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register character, 609880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 609980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += character; 61003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(hash, character); 610180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 10; 610280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 610380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(scratch, 10); 61043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(hash, scratch); 610580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 6; 610680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 6107692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ shr(scratch, 6); 61083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(hash, scratch); 610980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 611080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 611180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 611280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashGetHash(MacroAssembler* masm, 611380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 611480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch) { 611580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 3; 611680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 611780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(scratch, 3); 61183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(hash, scratch); 611980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 11; 612080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 6121692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ shr(scratch, 11); 61223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ xor_(hash, scratch); 612380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 15; 612480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch, hash); 612580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ shl(scratch, 15); 61263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(hash, scratch); 612780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6128c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ and_(hash, String::kHashBitMask); 6129692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch 613080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // if (hash == 0) hash = 27; 6131257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label hash_not_zero; 6132257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &hash_not_zero, Label::kNear); 6133c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ mov(hash, Immediate(StringHasher::kZeroHash)); 613480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&hash_not_zero); 613580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 613680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 613780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 613880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid SubStringStub::Generate(MacroAssembler* masm) { 613980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 614080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 614180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 614280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[0]: return address 614380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[4]: to 614480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[8]: from 614580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[12]: string 614680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 614780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure first argument is a string. 614880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, 3 * kPointerSize)); 614980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 61503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(eax, &runtime); 615180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); 615280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ j(NegateCondition(is_string), &runtime); 615380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 615480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: string 615580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ebx: instance type 615680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 615780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate length of sub string using the smi values. 615880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index. 61593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(ecx, &runtime); 616080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index. 61613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(edx, &runtime); 61623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(ecx, edx); 616380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(ecx, FieldOperand(eax, String::kLengthOffset)); 61643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label not_original_string; 61653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, ¬_original_string, Label::kNear); 61663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Counters* counters = masm->isolate()->counters(); 61673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ IncrementCounter(counters->sub_string_native(), 1); 61683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(3 * kPointerSize); 61693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(¬_original_string); 61703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6171c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch // eax: string 6172c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch // ebx: instance type 61733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ecx: sub string length (smi) 6174c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch // edx: from index (smi) 61753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Deal with different string types: update the index if necessary 61763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // and put the underlying string into edi. 61773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label underlying_unpacked, sliced_string, seq_or_external_string; 61783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // If the string is not indirect, it can only be sequential or external. 61793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); 61803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kIsIndirectStringMask != 0); 61813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(ebx, Immediate(kIsIndirectStringMask)); 61823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(zero, &seq_or_external_string, Label::kNear); 6183c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch 61843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Factory* factory = masm->isolate()->factory(); 61853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(ebx, Immediate(kSlicedNotConsMask)); 61863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_zero, &sliced_string, Label::kNear); 61873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Cons string. Check whether it is flat, then fetch first part. 61883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Flat cons strings have an empty second part. 61893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(FieldOperand(eax, ConsString::kSecondOffset), 61903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch factory->empty_string()); 61913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &runtime); 61923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edi, FieldOperand(eax, ConsString::kFirstOffset)); 61933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Update instance type. 61943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); 61953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 61963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&underlying_unpacked, Label::kNear); 6197c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch 61983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&sliced_string); 61993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Sliced string. Fetch parent and adjust start index by offset. 62003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset)); 62013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edi, FieldOperand(eax, SlicedString::kParentOffset)); 62023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Update instance type. 62033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); 620485b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 62053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&underlying_unpacked, Label::kNear); 62063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 62073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&seq_or_external_string); 62083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Sequential or external string. Just move string to the expected register. 62093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edi, eax); 62103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 62113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&underlying_unpacked); 621280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 621369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (FLAG_string_slices) { 621469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label copy_routine; 62153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // edi: underlying subject string 62163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ebx: instance type of underlying subject string 62173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // edx: adjusted start index (smi) 62183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ecx: length (smi) 62193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ecx, Immediate(Smi::FromInt(SlicedString::kMinLength))); 622069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Short slice. Copy instead of slicing. 622169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(less, ©_routine); 622269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Allocate new sliced string. At this point we do not reload the instance 622369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // type including the string encoding because we simply rely on the info 622469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // provided by the original string. It does not matter if the original 622569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // string's encoding is wrong because we always have to recheck encoding of 622669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // the newly created string's parent anyways due to externalized strings. 622769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label two_byte_slice, set_slice_header; 6228589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 6229589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 6230589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ test(ebx, Immediate(kStringEncodingMask)); 623169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ j(zero, &two_byte_slice, Label::kNear); 623269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ AllocateAsciiSlicedString(eax, ebx, no_reg, &runtime); 623369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&set_slice_header, Label::kNear); 623469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&two_byte_slice); 6235589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime); 623669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&set_slice_header); 623769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx); 623869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(FieldOperand(eax, SlicedString::kHashFieldOffset), 623969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Immediate(String::kEmptyHashField)); 62403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(FieldOperand(eax, SlicedString::kParentOffset), edi); 62413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx); 62423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ IncrementCounter(counters->sub_string_native(), 1); 62433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(3 * kPointerSize); 624469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 624569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(©_routine); 624669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 624769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 62483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // edi: underlying subject string 62493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ebx: instance type of underlying subject string 62503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // edx: adjusted start index (smi) 62513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ecx: length (smi) 62523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // The subject string can only be external or sequential string of either 62533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // encoding at this point. 62543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label two_byte_sequential, runtime_drop_two, sequential_string; 62553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kExternalStringTag != 0); 62563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kSeqStringTag == 0); 62573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test_b(ebx, kExternalStringTag); 62583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(zero, &sequential_string); 62593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 62603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Handle external string. 62613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Rule out short external strings. 62623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_CHECK(kShortExternalStringTag != 0); 62633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test_b(ebx, kShortExternalStringMask); 62643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_zero, &runtime); 62653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edi, FieldOperand(edi, ExternalString::kResourceDataOffset)); 62663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Move the pointer so that offset-wise, it looks like a sequential string. 62673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); 62683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(edi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 626980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 62703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&sequential_string); 62713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Stash away (adjusted) index and (underlying) string. 62723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(edx); 62733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(edi); 62743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ SmiUntag(ecx); 62753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0); 62763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test_b(ebx, kStringEncodingMask); 62773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(zero, &two_byte_sequential); 62783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 62793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Sequential ASCII string. Allocate the result. 62803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime_drop_two); 628180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 628280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 628380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result string length 628480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, esi); // esi used by following code. 628580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 628680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, eax); 62873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(edi, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 628880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load string argument and locate character of sub string start. 62893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(esi); 62903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(ebx); 629180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiUntag(ebx); 62923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lea(esi, FieldOperand(esi, ebx, times_1, SeqAsciiString::kHeaderSize)); 629380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 629480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 629580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result length 629680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: original value of esi 629780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: first character of result 629880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: character of sub string start 629980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); 630080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(esi, edx); // Restore esi. 630144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->sub_string_native(), 1); 630280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 630380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 63043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&two_byte_sequential); 63053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Sequential two-byte string. Allocate the result. 63063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime_drop_two); 630780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 630880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 630980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result string length 631080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, esi); // esi used by following code. 631180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 631280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edi, eax); 63133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(edi, 631480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 631580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load string argument and locate character of sub string start. 63163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(esi); 63173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(ebx); 631880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // As from is a smi it is 2 times the value which matches the size of a two 631980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // byte character. 632080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 632180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 63223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lea(esi, FieldOperand(esi, ebx, times_1, SeqTwoByteString::kHeaderSize)); 632380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 632480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // eax: result string 632580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ecx: result length 632680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edx: original value of esi 632780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // edi: first character of result 632880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esi: character of sub string start 632980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); 633080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(esi, edx); // Restore esi. 633144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->sub_string_native(), 1); 633280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(3 * kPointerSize); 633380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 63343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Drop pushed values on the stack before tail call. 63353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&runtime_drop_two); 63363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Drop(2); 63373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 633880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump to runtime to create the sub string. 633980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 634080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kSubString, 3, 1); 634180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 634280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 634380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, 6345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left, 6346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right, 6347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch1, 6348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch2) { 6349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register length = scratch1; 6350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare lengths. 6352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label strings_not_equal, check_zero_length; 6353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(length, FieldOperand(left, String::kLengthOffset)); 6354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(length, FieldOperand(right, String::kLengthOffset)); 6355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &check_zero_length, Label::kNear); 6356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&strings_not_equal); 6357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL))); 6358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 6359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the length is zero. 6361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label compare_chars; 6362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&check_zero_length); 6363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 63643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(length, length); 6365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &compare_chars, Label::kNear); 6366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 6368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare characters. 6370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&compare_chars); 6371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2, 6372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch &strings_not_equal, Label::kNear); 6373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Characters are equal. 6375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 6377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 638080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, 638180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register left, 638280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register right, 638380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 638480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 638580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch3) { 638644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 638744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_compare_native(), 1); 638880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 638980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find minimum length. 6390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label left_shorter; 639180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); 639280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch3, scratch1); 639380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); 639480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 639580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register length_delta = scratch3; 639680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(less_equal, &left_shorter, Label::kNear); 639880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Right string is shorter. Change scratch1 to be length of right string. 63993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(scratch1, length_delta); 640080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&left_shorter); 640180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 640280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register min_length = scratch1; 640380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 640480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If either length is zero, just compare lengths. 6405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label compare_lengths; 64063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(min_length, min_length); 6407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &compare_lengths, Label::kNear); 640880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare characters. 6410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label result_not_equal; 6411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2, 6412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch &result_not_equal, Label::kNear); 641380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 641480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compare lengths - strings up to min-length are equal. 641580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&compare_lengths); 64163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(length_delta, length_delta); 6417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &result_not_equal, Label::kNear); 641880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 641980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is EQUAL. 642080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(EQUAL == 0); 642180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 642280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 642380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 642480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label result_greater; 642680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&result_not_equal); 6427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(greater, &result_greater, Label::kNear); 642880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 642980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is LESS. 643080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(LESS))); 643180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 643280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 643380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result is GREATER. 643480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&result_greater); 643580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(GREATER))); 643680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(0); 643780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 643880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 643980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateAsciiCharsCompareLoop( 6441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 6442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left, 6443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right, 6444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register length, 6445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch, 6446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* chars_not_equal, 6447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label::Distance chars_not_equal_near) { 6448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Change index to run from -length to -1 by adding length to string 6449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // start. This means that loop ends when index reaches zero, which 6450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // doesn't need an additional compare. 6451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiUntag(length); 6452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(left, 6453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize)); 6454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(right, 6455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize)); 6456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ neg(length); 6457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register index = length; // index = -length; 6458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare loop. 6460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop; 6461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&loop); 6462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov_b(scratch, Operand(left, index, times_1, 0)); 6463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmpb(scratch, Operand(right, index, times_1, 0)); 6464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, chars_not_equal, chars_not_equal_near); 64653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ inc(index); 6466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &loop); 6467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 647080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::Generate(MacroAssembler* masm) { 647180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 647280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 647380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 647480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[0]: return address 647580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[4]: right string 647680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // esp[8]: left string 647780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 647880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(edx, Operand(esp, 2 * kPointerSize)); // left 647980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(eax, Operand(esp, 1 * kPointerSize)); // right 648080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_same; 64823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(edx, eax); 6483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, ¬_same, Label::kNear); 648480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(EQUAL == 0); 648580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 648680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 648744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(masm->isolate()->counters()->string_compare_native(), 1); 648880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret(2 * kPointerSize); 648980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 649080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_same); 649180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 64923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Check that both objects are sequential ASCII strings. 649380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); 649480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 64953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Compare flat ASCII strings. 649680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Drop arguments from the stack. 649780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(ecx); 64983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(esp, Immediate(2 * kPointerSize)); 649980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(ecx); 650080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); 650180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 650280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 650380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // tagged as a small integer. 650480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 650580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 650680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 650780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6508b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateSmis(MacroAssembler* masm) { 6510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(state_ == CompareIC::SMIS); 6511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 65123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, edx); 65133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ or_(ecx, eax); 65143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(ecx, &miss, Label::kNear); 6515b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6516b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (GetCondition() == equal) { 6517b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // For equality we do not care about the sign of the result. 65183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(eax, edx); 6519b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 6520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done; 65213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(edx, eax); 6522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(no_overflow, &done, Label::kNear); 6523b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Correct sign of result in case of overflow. 6524b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ not_(edx); 6525b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&done); 6526b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, edx); 6527b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 6528b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 6529b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6530b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&miss); 6531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateMiss(masm); 6532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 6533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6534b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { 6536b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(state_ == CompareIC::HEAP_NUMBERS); 6537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label generic_stub; 65393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label unordered, maybe_undefined1, maybe_undefined2; 6540257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 65413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, edx); 65423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(ecx, eax); 65433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(ecx, &generic_stub, Label::kNear); 6544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx); 65463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &maybe_undefined1, Label::kNear); 6547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); 65483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &maybe_undefined2, Label::kNear); 6549b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6550b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Inlining the double comparison and falling back to the general compare 6551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // stub if NaN is involved or SS2 or CMOV is unsupported. 65528b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { 6553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope scope1(SSE2); 6554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope scope2(CMOV); 6555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Load left and right operand 6557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 6558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 6559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Compare operands 6561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ucomisd(xmm0, xmm1); 6562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Don't base result on EFLAGS when a NaN is involved. 6564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(parity_even, &unordered, Label::kNear); 6565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6566b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Return a result of -1, 0, or 1, based on EFLAGS. 6567b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Performing mov, because xor would destroy the flag register. 6568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(eax, 0); // equal 6569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Immediate(Smi::FromInt(1))); 65703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmov(above, eax, ecx); 6571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(ecx, Immediate(Smi::FromInt(-1))); 65723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmov(below, eax, ecx); 6573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 6574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 6575b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 65763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&unordered); 6577b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); 6578b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&generic_stub); 6579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); 6580b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 65813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&maybe_undefined1); 65823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (Token::IsOrderedRelationalCompareOp(op_)) { 65833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(eax, Immediate(masm->isolate()->factory()->undefined_value())); 65843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &miss); 65853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); 65863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &maybe_undefined2, Label::kNear); 65873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&unordered); 65883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 65893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 65903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&maybe_undefined2); 65913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (Token::IsOrderedRelationalCompareOp(op_)) { 65923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(edx, Immediate(masm->isolate()->factory()->undefined_value())); 65933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(equal, &unordered); 65943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 65953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6596b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&miss); 6597b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateMiss(masm); 6598b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 6599b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6600b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateSymbols(MacroAssembler* masm) { 6602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(state_ == CompareIC::SYMBOLS); 6603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(GetCondition() == equal); 6604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 6606257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = edx; 6607257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = eax; 6608257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp1 = ecx; 6609257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp2 = ebx; 6610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6611257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are heap objects. 6612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 66133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(tmp1, left); 6614257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 66153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(tmp1, right); 66163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(tmp1, &miss, Label::kNear); 6617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6618257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are symbols. 6619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); 6620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); 6621257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); 6622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); 6623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSymbolTag != 0); 66243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(tmp1, tmp2); 6625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(tmp1, Immediate(kIsSymbolMask)); 6626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &miss, Label::kNear); 6627257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Symbols are compared by identity. 6629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done; 66303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(left, right); 6631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Make sure eax is non-zero. At this point input operands are 6632257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // guaranteed to be non-zero. 6633257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(right.is(eax)); 6634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &done, Label::kNear); 6635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(EQUAL == 0); 6636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 6637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&done); 6639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 6640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6641257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&miss); 6642257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateMiss(masm); 6643257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6646257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateStrings(MacroAssembler* masm) { 6647257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(state_ == CompareIC::STRINGS); 6648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 6649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 66503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch bool equality = Token::IsEqualityOp(op_); 66513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 6653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = edx; 6654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = eax; 6655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp1 = ecx; 6656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp2 = ebx; 6657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp3 = edi; 6658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are heap objects. 66603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(tmp1, left); 6661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 66623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(tmp1, right); 66633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(tmp1, &miss); 6664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are strings. This leaves the instance 6666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // types loaded in tmp1 and tmp2. 6667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); 6668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); 6669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); 6670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); 6671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(tmp3, tmp1); 6672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kNotStringTag != 0); 66733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ or_(tmp3, tmp2); 6674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test(tmp3, Immediate(kIsNotStringMask)); 6675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, &miss); 6676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Fast check for identical strings. 6678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label not_same; 66793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(left, right); 6680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, ¬_same, Label::kNear); 6681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(EQUAL == 0); 6682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 6683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(0); 6685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle not identical strings. 6687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(¬_same); 6688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both strings are symbols. If they are, we're done 66903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // because we already know they are not identical. But in the case of 66913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // non-equality compare, we still need to determine the order. 66923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (equality) { 66933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label do_compare; 66943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kSymbolTag != 0); 66953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(tmp1, tmp2); 66963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(tmp1, Immediate(kIsSymbolMask)); 66973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(zero, &do_compare, Label::kNear); 66983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Make sure eax is non-zero. At this point input operands are 66993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // guaranteed to be non-zero. 67003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(right.is(eax)); 67013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(0); 67023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&do_compare); 67033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 6704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both strings are sequential ASCII. 6706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label runtime; 6707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime); 6708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare flat ASCII strings. Returns when done. 67103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (equality) { 67113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch StringCompareStub::GenerateFlatAsciiStringEquals( 67123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm, left, right, tmp1, tmp2); 67133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 67143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch StringCompareStub::GenerateCompareFlatAsciiStrings( 67153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm, left, right, tmp1, tmp2, tmp3); 67163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 6717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle more complex cases in runtime. 6719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&runtime); 6720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ pop(tmp1); // Return address. 6721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(left); 6722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(right); 6723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(tmp1); 67243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (equality) { 67253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kStringEquals, 2, 1); 67263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 67273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 67283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 6729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&miss); 6731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateMiss(masm); 6732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6735b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateObjects(MacroAssembler* masm) { 6736b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(state_ == CompareIC::OBJECTS); 6737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 67383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, edx); 67393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(ecx, eax); 67403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(ecx, &miss, Label::kNear); 6741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); 6743257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 6744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); 6745257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_equal, &miss, Label::kNear); 6746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(GetCondition() == equal); 67483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(eax, edx); 6749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 6750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&miss); 6752b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateMiss(masm); 6753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 6754b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 67563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) { 67573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label miss; 67583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, edx); 67593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(ecx, eax); 67603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfSmi(ecx, &miss, Label::kNear); 6761c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch 67623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 67633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 67643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ecx, known_map_); 67653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &miss, Label::kNear); 67663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ebx, known_map_); 67673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(not_equal, &miss, Label::kNear); 6768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 67693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(eax, edx); 67703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(0); 67713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 67723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&miss); 67733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateMiss(masm); 67743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 6775c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch 67763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 67773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid ICCompareStub::GenerateMiss(MacroAssembler* masm) { 67783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 67793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Call the runtime system in a fresh internal frame. 67803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss), 67813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm->isolate()); 67823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FrameScope scope(masm, StackFrame::INTERNAL); 67833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(edx); // Preserve edx and eax. 67843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(eax); 67853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(edx); // And also use them as the arguments. 67863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(eax); 67873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(Immediate(Smi::FromInt(op_))); 67883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallExternalReference(miss, 3); 67893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Compute the entry point of the rewritten stub. 67903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lea(edi, FieldOperand(eax, Code::kHeaderSize)); 67913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(eax); 67923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(edx); 67933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 6794b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6795b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Do a tail call to the rewritten stub. 67963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(edi); 6797b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 6798b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6799b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Helper function used to check that the dictionary doesn't contain 6801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// the property. This function may return false negatives, so miss_label 6802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// must always call a backup property check that is complete. 6803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// This function is safe to call if the receiver has fast properties. 6804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Name must be a symbol and receiver must be a heap object. 68053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, 68063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label* miss, 68073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label* done, 68083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Register properties, 68093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Handle<String> name, 68103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Register r0) { 6811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(name->IsSymbol()); 6812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If names of slots in range from 1 to kProbes - 1 for the hash value are 6814257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // not equal to the name and kProbes-th slot is not used (its name is the 6815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // undefined value), it guarantees the hash table doesn't contain the 6816257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // property. It's true even if some slots represent deleted properties 68173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // (their names are the hole value). 6818257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = 0; i < kInlinedProbes; i++) { 6819257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 6820257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register index = r0; 6821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Capacity is smi 2^n. 6822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(index, FieldOperand(properties, kCapacityOffset)); 6823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ dec(index); 68243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(index, 68253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Immediate(Smi::FromInt(name->Hash() + 6826257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionary::GetProbeOffset(i)))); 6827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the entry size. 6829257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 6830257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. 6831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register entity_name = r0; 6832257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Having undefined at this place means the name is not contained. 6833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT_EQ(kSmiTagSize, 1); 6834257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(entity_name, Operand(properties, index, times_half_pointer_size, 6835257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kElementsStartOffset - kHeapObjectTag)); 6836257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(entity_name, masm->isolate()->factory()->undefined_value()); 6837257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, done); 6838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6839257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Stop if found the property. 6840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(entity_name, Handle<String>(name)); 6841257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, miss); 6842257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 68433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label the_hole; 68443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Check for the hole and skip. 68453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(entity_name, masm->isolate()->factory()->the_hole_value()); 68463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ j(equal, &the_hole, Label::kNear); 68473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6848257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the entry name is not a symbol. 6849257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); 6850257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset), 6851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kIsSymbolMask); 6852257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, miss); 68533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&the_hole); 6854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionaryLookupStub stub(properties, 6857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 6858257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 6859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionaryLookupStub::NEGATIVE_LOOKUP); 6860257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(Immediate(Handle<Object>(name))); 6861257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(Immediate(name->Hash())); 68623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallStub(&stub); 68633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(r0, r0); 6864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(not_zero, miss); 6865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(done); 6866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6868257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6869257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Probe the string dictionary in the |elements| register. Jump to the 6870257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// |done| label if a property with the given name is found leaving the 6871257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// index into the dictionary in |r0|. Jump to the |miss| label 6872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// otherwise. 6873257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, 6874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* miss, 6875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* done, 6876257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register elements, 6877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register name, 6878257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register r0, 6879257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register r1) { 68803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(!elements.is(r0)); 68813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(!elements.is(r1)); 68823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(!name.is(r0)); 68833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(!name.is(r1)); 68843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Assert that name contains a string. 6886257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (FLAG_debug_code) __ AbortIfNotString(name); 6887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r1, FieldOperand(elements, kCapacityOffset)); 6889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(r1, kSmiTagSize); // convert smi to int 6890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ dec(r1); 6891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Generate an unrolled loop that performs a few probes before 6893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // giving up. Measurements done on Gmail indicate that 2 probes 6894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // cover ~93% of loads from dictionaries. 6895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = 0; i < kInlinedProbes; i++) { 6896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 6897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); 6898257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(r0, String::kHashShift); 6899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i > 0) { 69003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r0, Immediate(StringDictionary::GetProbeOffset(i))); 6901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 69023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(r0, r1); 6903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the entry size. 6905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 6906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3 6907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the key is identical to the name. 6909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(name, Operand(elements, 6910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 6911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch times_4, 6912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kElementsStartOffset - kHeapObjectTag)); 6913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, done); 6914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionaryLookupStub stub(elements, 6917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r1, 6918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r0, 6919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch POSITIVE_LOOKUP); 6920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(name); 6921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); 6922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ shr(r0, String::kHashShift); 6923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(r0); 6924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallStub(&stub); 6925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 69263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ test(r1, r1); 6927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, miss); 6928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(done); 6929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6932257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::Generate(MacroAssembler* masm) { 69333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // This stub overrides SometimesSetsUpAFrame() to return false. That means 69343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // we cannot call anything that could cause a GC from this stub. 6935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Stack frame on entry: 6936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // esp[0 * kPointerSize]: return address. 6937257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // esp[1 * kPointerSize]: key's hash. 6938257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // esp[2 * kPointerSize]: key. 6939257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers: 6940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // dictionary_: StringDictionary to probe. 6941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // result_: used as scratch. 6942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // index_: will hold an index of entry if lookup is successful. 6943257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // might alias with result_. 6944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Returns: 6945257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // result_ is zero if lookup failed, non zero otherwise. 6946257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6947257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label in_dictionary, maybe_in_dictionary, not_in_dictionary; 6948257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch = result_; 6950257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset)); 6952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ dec(scratch); 6953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiUntag(scratch); 6954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(scratch); 6955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If names of slots in range from 1 to kProbes - 1 for the hash value are 6957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // not equal to the name and kProbes-th slot is not used (its name is the 6958257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // undefined value), it guarantees the hash table doesn't contain the 6959257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // property. It's true even if some slots represent deleted properties 6960257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // (their names are the null value). 6961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = kInlinedProbes; i < kTotalProbes; i++) { 6962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 6963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, Operand(esp, 2 * kPointerSize)); 6964257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i > 0) { 69653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(scratch, Immediate(StringDictionary::GetProbeOffset(i))); 6966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(scratch, Operand(esp, 0)); 6968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6969257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the entry size. 6970257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 6971257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. 6972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6973257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Having undefined at this place means the name is not contained. 6974257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT_EQ(kSmiTagSize, 1); 6975257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, Operand(dictionary_, 6976257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch index_, 6977257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch times_pointer_size, 6978257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kElementsStartOffset - kHeapObjectTag)); 6979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(scratch, masm->isolate()->factory()->undefined_value()); 6980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, ¬_in_dictionary); 6981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6982257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Stop if found the property. 6983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(scratch, Operand(esp, 3 * kPointerSize)); 6984257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(equal, &in_dictionary); 6985257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6986257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { 6987257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If we hit a non symbol key during negative lookup 6988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // we have to bailout as this key might be equal to the 6989257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // key we are looking for. 6990257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6991257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the entry name is not a symbol. 6992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); 6993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset), 6994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch kIsSymbolMask); 6995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ j(zero, &maybe_in_dictionary); 6996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&maybe_in_dictionary); 7000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If we are doing negative lookup then probing failure should be 7001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // treated as a lookup success. For positive lookup probing failure 7002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // should be treated as lookup failure. 7003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (mode_ == POSITIVE_LOOKUP) { 7004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(result_, Immediate(0)); 7005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Drop(1); 7006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 7007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 7008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&in_dictionary); 7010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(result_, Immediate(1)); 7011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Drop(1); 7012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 7013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(¬_in_dictionary); 7015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(result_, Immediate(0)); 7016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Drop(1); 7017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ret(2 * kPointerSize); 7018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 7019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 70213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstruct AheadOfTimeWriteBarrierStubList { 70223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Register object, value, address; 70233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch RememberedSetAction action; 70243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}; 70253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 70263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 70273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#define REG(Name) { kRegister_ ## Name ## _Code } 70283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 70293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { 70303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Used in RegExpExecStub. 70313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(ebx), REG(eax), REG(edi), EMIT_REMEMBERED_SET }, 70323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Used in CompileArrayPushCall. 70333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(ebx), REG(ecx), REG(edx), EMIT_REMEMBERED_SET }, 70343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(ebx), REG(edi), REG(edx), OMIT_REMEMBERED_SET }, 70353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Used in CompileStoreGlobal and CallFunctionStub. 70363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(ebx), REG(ecx), REG(edx), OMIT_REMEMBERED_SET }, 70373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Used in StoreStubCompiler::CompileStoreField and 70383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField. 70393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(edx), REG(ecx), REG(ebx), EMIT_REMEMBERED_SET }, 70403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // GenerateStoreField calls the stub with two different permutations of 70413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // registers. This is the second. 70423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(ebx), REG(ecx), REG(edx), EMIT_REMEMBERED_SET }, 70433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // StoreIC::GenerateNormal via GenerateDictionaryStore 70443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(ebx), REG(edi), REG(edx), EMIT_REMEMBERED_SET }, 70453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // KeyedStoreIC::GenerateGeneric. 70463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(ebx), REG(edx), REG(ecx), EMIT_REMEMBERED_SET}, 70473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // KeyedStoreStubCompiler::GenerateStoreFastElement. 70483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(edi), REG(ebx), REG(ecx), EMIT_REMEMBERED_SET}, 70493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(edx), REG(edi), REG(ebx), EMIT_REMEMBERED_SET}, 70503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ElementsTransitionGenerator::GenerateSmiOnlyToObject 70513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble 70523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // and ElementsTransitionGenerator::GenerateDoubleToObject 70533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(edx), REG(ebx), REG(edi), EMIT_REMEMBERED_SET}, 70543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(edx), REG(ebx), REG(edi), OMIT_REMEMBERED_SET}, 70553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ElementsTransitionGenerator::GenerateDoubleToObject 70563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(eax), REG(edx), REG(esi), EMIT_REMEMBERED_SET}, 70573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(edx), REG(eax), REG(edi), EMIT_REMEMBERED_SET}, 70583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // StoreArrayLiteralElementStub::Generate 70593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(ebx), REG(eax), REG(ecx), EMIT_REMEMBERED_SET}, 70603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Null termination. 70613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(no_reg), REG(no_reg), REG(no_reg), EMIT_REMEMBERED_SET} 70623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}; 70633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 70643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#undef REG 70653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 70663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool RecordWriteStub::IsPregenerated() { 70673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; 70683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch !entry->object.is(no_reg); 70693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch entry++) { 70703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (object_.is(entry->object) && 70713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch value_.is(entry->value) && 70723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch address_.is(entry->address) && 70733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch remembered_set_action_ == entry->action && 70743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch save_fp_regs_mode_ == kDontSaveFPRegs) { 70753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return true; 70763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 70773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 70783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return false; 70793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 70803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 70813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 70823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime() { 70833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch StoreBufferOverflowStub stub1(kDontSaveFPRegs); 70843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch stub1.GetCode()->set_is_pregenerated(true); 70853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 70863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CpuFeatures::TryForceFeatureScope scope(SSE2); 70873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (CpuFeatures::IsSupported(SSE2)) { 70883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch StoreBufferOverflowStub stub2(kSaveFPRegs); 70893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch stub2.GetCode()->set_is_pregenerated(true); 70903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 70913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 70923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 70933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 70943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::GenerateFixedRegStubsAheadOfTime() { 70953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; 70963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch !entry->object.is(no_reg); 70973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch entry++) { 70983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch RecordWriteStub stub(entry->object, 70993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch entry->value, 71003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch entry->address, 71013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch entry->action, 71023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kDontSaveFPRegs); 71033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch stub.GetCode()->set_is_pregenerated(true); 71043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 71053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 71063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Takes the input in 3 registers: address_ value_ and object_. A pointer to 71093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// the value has just been written into the object, now this stub makes sure 71103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// we keep the GC informed. The word in the object where the value has been 71113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// written is in the address register. 71123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::Generate(MacroAssembler* masm) { 71133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label skip_to_incremental_noncompacting; 71143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label skip_to_incremental_compacting; 71153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // The first two instructions are generated with labels so as to get the 71173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // offset fixed up correctly by the bind(Label*) call. We patch it back and 71183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // forth between a compare instructions (a nop in this position) and the 71193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // real branch when we start and stop incremental heap marking. 71203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&skip_to_incremental_noncompacting, Label::kNear); 71213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&skip_to_incremental_compacting, Label::kFar); 71223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (remembered_set_action_ == EMIT_REMEMBERED_SET) { 71243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ RememberedSetHelper(object_, 71253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch address_, 71263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch value_, 71273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch save_fp_regs_mode_, 71283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler::kReturnAtEnd); 71293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 71303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(0); 71313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 71323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&skip_to_incremental_noncompacting); 71343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateIncremental(masm, INCREMENTAL); 71353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&skip_to_incremental_compacting); 71373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateIncremental(masm, INCREMENTAL_COMPACTION); 71383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Initial mode of the stub is expected to be STORE_BUFFER_ONLY. 71403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Will be checked in IncrementalMarking::ActivateGeneratedStub. 71413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm->set_byte_at(0, kTwoByteNopInstruction); 71423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm->set_byte_at(2, kFiveByteNopInstruction); 71433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 71443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) { 71473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.Save(masm); 71483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (remembered_set_action_ == EMIT_REMEMBERED_SET) { 71503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label dont_need_remembered_set; 71513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(regs_.scratch0(), Operand(regs_.address(), 0)); 71533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfNotInNewSpace(regs_.scratch0(), // Value. 71543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.scratch0(), 71553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &dont_need_remembered_set); 71563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CheckPageFlag(regs_.object(), 71583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.scratch0(), 71593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1 << MemoryChunk::SCAN_ON_SCAVENGE, 71603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch not_zero, 71613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &dont_need_remembered_set); 71623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // First notify the incremental marker if necessary, then update the 71643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // remembered set. 71653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CheckNeedsToInformIncrementalMarker( 71663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm, 71673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, 71683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch mode); 71693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch InformIncrementalMarker(masm, mode); 71703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.Restore(masm); 71713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ RememberedSetHelper(object_, 71723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch address_, 71733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch value_, 71743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch save_fp_regs_mode_, 71753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler::kReturnAtEnd); 71763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&dont_need_remembered_set); 71783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 71793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CheckNeedsToInformIncrementalMarker( 71813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm, 71823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kReturnOnNoNeedToInformIncrementalMarker, 71833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch mode); 71843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch InformIncrementalMarker(masm, mode); 71853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.Restore(masm); 71863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(0); 71873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 71883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) { 71913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_); 71923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int argument_count = 3; 71933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ PrepareCallCFunction(argument_count, regs_.scratch0()); 71943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(Operand(esp, 0 * kPointerSize), regs_.object()); 71953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (mode == INCREMENTAL_COMPACTION) { 71963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(Operand(esp, 1 * kPointerSize), regs_.address()); // Slot. 71973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 71983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(mode == INCREMENTAL); 71993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(regs_.scratch0(), Operand(regs_.address(), 0)); 72003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(Operand(esp, 1 * kPointerSize), regs_.scratch0()); // Value. 72013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 72023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(Operand(esp, 2 * kPointerSize), 72033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Immediate(ExternalReference::isolate_address())); 72043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch AllowExternalCallThatCantCauseGC scope(masm); 72063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (mode == INCREMENTAL_COMPACTION) { 72073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallCFunction( 72083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference::incremental_evacuation_record_write_function( 72093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm->isolate()), 72103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch argument_count); 72113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 72123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(mode == INCREMENTAL); 72133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallCFunction( 72143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference::incremental_marking_record_write_function( 72153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm->isolate()), 72163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch argument_count); 72173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 72183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_); 72193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 72203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::CheckNeedsToInformIncrementalMarker( 72233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler* masm, 72243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch OnNoNeedToInformIncrementalMarker on_no_need, 72253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Mode mode) { 72263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label object_is_black, need_incremental, need_incremental_pop_object; 72273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Let's look at the color of the object: If it is not black we don't have 72293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // to inform the incremental marker. 72303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfBlack(regs_.object(), 72313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.scratch0(), 72323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.scratch1(), 72333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &object_is_black, 72343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label::kNear); 72353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.Restore(masm); 72373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { 72383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ RememberedSetHelper(object_, 72393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch address_, 72403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch value_, 72413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch save_fp_regs_mode_, 72423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler::kReturnAtEnd); 72433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 72443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(0); 72453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 72463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&object_is_black); 72483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Get the value from the slot. 72503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(regs_.scratch0(), Operand(regs_.address(), 0)); 72513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (mode == INCREMENTAL_COMPACTION) { 72533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label ensure_not_white; 72543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CheckPageFlag(regs_.scratch0(), // Contains value. 72563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.scratch1(), // Scratch. 72573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MemoryChunk::kEvacuationCandidateMask, 72583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch zero, 72593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &ensure_not_white, 72603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label::kNear); 72613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CheckPageFlag(regs_.object(), 72633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.scratch1(), // Scratch. 72643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MemoryChunk::kSkipEvacuationSlotsRecordingMask, 72653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch not_zero, 72663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &ensure_not_white, 72673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label::kNear); 72683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&need_incremental); 72703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&ensure_not_white); 72723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 72733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // We need an extra register for this, so we push the object register 72753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // temporarily. 72763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(regs_.object()); 72773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ EnsureNotWhite(regs_.scratch0(), // The value. 72783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.scratch1(), // Scratch. 72793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.object(), // Scratch. 72803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &need_incremental_pop_object, 72813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label::kNear); 72823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(regs_.object()); 72833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.Restore(masm); 72853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { 72863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ RememberedSetHelper(object_, 72873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch address_, 72883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch value_, 72893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch save_fp_regs_mode_, 72903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler::kReturnAtEnd); 72913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 72923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(0); 72933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 72943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&need_incremental_pop_object); 72963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(regs_.object()); 72973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&need_incremental); 72993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Fall through when we need to inform the incremental marker. 73013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 73023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) { 73053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ----------- S t a t e ------------- 73063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // -- eax : element value to store 73073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // -- ebx : array literal 73083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // -- edi : map of array literal 73093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // -- ecx : element index as smi 73103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // -- edx : array literal index in function 73113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // -- esp[0] : return address 73123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ----------------------------------- 73133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label element_done; 73153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label double_elements; 73163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label smi_element; 73173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label slow_elements; 73183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label slow_elements_from_double; 73193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label fast_elements; 73203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CheckFastElements(edi, &double_elements); 73223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS 73243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfSmi(eax, &smi_element); 73253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CheckFastSmiOnlyElements(edi, &fast_elements, Label::kNear); 73263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Store into the array literal requires a elements transition. Call into 73283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // the runtime. 73293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&slow_elements); 73313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(edi); // Pop return address and remember to put back later for tail 73323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // call. 73333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(ebx); 73343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(ecx); 73353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(eax); 73363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 73373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); 73383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(edx); 73393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(edi); // Return return address so that tail call returns to right 73403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // place. 73413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1); 73423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&slow_elements_from_double); 73443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(edx); 73453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&slow_elements); 73463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Array literal has ElementsKind of FAST_ELEMENTS and value is an object. 73483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&fast_elements); 73493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); 73503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lea(ecx, FieldOperand(ebx, ecx, times_half_pointer_size, 73513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FixedArrayBase::kHeaderSize)); 73523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(Operand(ecx, 0), eax); 73533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Update the write barrier for the array store. 73543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ RecordWrite(ebx, ecx, eax, 73553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kDontSaveFPRegs, 73563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch EMIT_REMEMBERED_SET, 73573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch OMIT_SMI_CHECK); 73583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(0); 73593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or 73613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // FAST_ELEMENTS, and value is Smi. 73623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&smi_element); 73633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); 73643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(FieldOperand(ebx, ecx, times_half_pointer_size, 73653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FixedArrayBase::kHeaderSize), eax); 73663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(0); 73673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS. 73693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&double_elements); 73703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(edx); 73723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(edx, FieldOperand(ebx, JSObject::kElementsOffset)); 73733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ StoreNumberToDoubleElements(eax, 73743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch edx, 73753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ecx, 73763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch edi, 73773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch xmm0, 73783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &slow_elements_from_double, 73793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch false); 73803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(edx); 73813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ret(0); 73823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 73833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 738480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#undef __ 738580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 738680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} } // namespace v8::internal 738780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 738880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif // V8_TARGET_ARCH_IA32 7389