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_ARM) 3180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "bootstrapper.h" 3380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "code-stubs.h" 3480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "regexp-macro-assembler.h" 3580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsennamespace v8 { 3780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsennamespace internal { 3880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#define __ ACCESS_MASM(masm) 4180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic void EmitIdenticalObjectComparison(MacroAssembler* masm, 4380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* slow, 441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Condition cond, 4580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool never_nan_nan); 4680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic void EmitSmiNonsmiComparison(MacroAssembler* masm, 4780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register lhs, 4880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register rhs, 4980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* lhs_not_nan, 5080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* slow, 5180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool strict); 521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockstatic void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cond); 5380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, 5480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register lhs, 5580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register rhs); 5680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 58257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Check if the operand is a heap number. 59257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void EmitCheckForHeapNumber(MacroAssembler* masm, Register operand, 60257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch1, Register scratch2, 61257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* not_a_heap_number) { 62257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(scratch1, FieldMemOperand(operand, HeapObject::kMapOffset)); 63257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ LoadRoot(scratch2, Heap::kHeapNumberMapRootIndex); 64257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(scratch1, scratch2); 65257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(ne, not_a_heap_number); 66257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 67257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 68257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid ToNumberStub::Generate(MacroAssembler* masm) { 701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // The ToNumber stub takes one argument in eax. 711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label check_heap_number, call_builtin; 723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(r0, &check_heap_number); 731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&check_heap_number); 76257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch EmitCheckForHeapNumber(masm, r0, r1, ip, &call_builtin); 771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&call_builtin); 801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(r0); 81257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); 821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 8580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewClosureStub::Generate(MacroAssembler* masm) { 8680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Create a new closure from the given function info in new 8780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // space. Set the context to the current context in cp. 8880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label gc; 8980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 9080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Pop the function info from the stack. 9180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(r3); 9280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 9380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Attempt to allocate new JSFunction in new space. 9480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateInNewSpace(JSFunction::kSize, 9580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen r0, 9680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen r1, 9780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen r2, 9880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &gc, 9980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen TAG_OBJECT); 10080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int map_index = (language_mode_ == CLASSIC_MODE) 1023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ? Context::FUNCTION_MAP_INDEX 1033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch : Context::STRICT_MODE_FUNCTION_MAP_INDEX; 10444f0eee88ff00398ff7f715fab053374d808c90dSteve Block 10580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compute the function map in the current global context and set that 10680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // as the map of the allocated object. 10780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); 10880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalContextOffset)); 10944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ ldr(r2, MemOperand(r2, Context::SlotOffset(map_index))); 11080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); 11180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 11280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Initialize the rest of the function. We don't have to update the 11380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // write barrier because the allocated object is in new space. 11480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(r1, Heap::kEmptyFixedArrayRootIndex); 11580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(r2, Heap::kTheHoleValueRootIndex); 116b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ LoadRoot(r4, Heap::kUndefinedValueRootIndex); 11780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r1, FieldMemOperand(r0, JSObject::kPropertiesOffset)); 11880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r1, FieldMemOperand(r0, JSObject::kElementsOffset)); 11980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r2, FieldMemOperand(r0, JSFunction::kPrototypeOrInitialMapOffset)); 12080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r3, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset)); 12180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(cp, FieldMemOperand(r0, JSFunction::kContextOffset)); 12280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r1, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); 123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ str(r4, FieldMemOperand(r0, JSFunction::kNextFunctionLinkOffset)); 124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 12580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Initialize the code pointer in the function to be the one 12680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // found in the shared function info object. 12780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, FieldMemOperand(r3, SharedFunctionInfo::kCodeOffset)); 12880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); 12980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r3, FieldMemOperand(r0, JSFunction::kCodeEntryOffset)); 13080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 13180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return result. The argument function info has been popped already. 13280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 13380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 13480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Create a new closure through the slower runtime call. 13580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&gc); 1368a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ LoadRoot(r4, Heap::kFalseValueRootIndex); 1378a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ Push(cp, r3, r4); 1388a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ TailCallRuntime(Runtime::kNewClosure, 3, 1); 13980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 14080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 14180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 14280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewContextStub::Generate(MacroAssembler* masm) { 14380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try to allocate the context in new space. 14480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label gc; 14580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int length = slots_ + Context::MIN_CONTEXT_SLOTS; 14680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 14780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Attempt to allocate the context in new space. 14880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateInNewSpace(FixedArray::SizeFor(length), 14980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen r0, 15080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen r1, 15180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen r2, 15280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &gc, 15380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen TAG_OBJECT); 15480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 15580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the function from the stack. 15680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, MemOperand(sp, 0)); 15780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up the object header. 1593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ LoadRoot(r1, Heap::kFunctionContextMapRootIndex); 16080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r2, Operand(Smi::FromInt(length))); 16180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r2, FieldMemOperand(r0, FixedArray::kLengthOffset)); 1623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); 16380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up the fixed slots, copy the global object from the previous context. 1653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); 16680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r1, Operand(Smi::FromInt(0))); 16780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r3, MemOperand(r0, Context::SlotOffset(Context::CLOSURE_INDEX))); 1683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(cp, MemOperand(r0, Context::SlotOffset(Context::PREVIOUS_INDEX))); 16980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r1, MemOperand(r0, Context::SlotOffset(Context::EXTENSION_INDEX))); 1703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r2, MemOperand(r0, Context::SlotOffset(Context::GLOBAL_INDEX))); 17180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 17280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Initialize the rest of the slots to undefined. 17380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); 17480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { 17580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r1, MemOperand(r0, Context::SlotOffset(i))); 17680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 17780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 17880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Remove the on-stack argument and return. 17980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(cp, r0); 18080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(); 18180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 18280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 18380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Need to collect. Call into runtime system. 18480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&gc); 1853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1); 18680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 18780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 18880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid FastNewBlockContextStub::Generate(MacroAssembler* masm) { 1903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Stack layout on entry: 1913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // 1923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // [sp]: function. 1933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // [sp + kPointerSize]: serialized scope info 1943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Try to allocate the context in new space. 1963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label gc; 1973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int length = slots_ + Context::MIN_CONTEXT_SLOTS; 1983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateInNewSpace(FixedArray::SizeFor(length), 1993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r0, r1, r2, &gc, TAG_OBJECT); 2003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load the function from the stack. 2023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r3, MemOperand(sp, 0)); 2033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load the serialized scope info from the stack. 2053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); 2063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up the object header. 2083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ LoadRoot(r2, Heap::kBlockContextMapRootIndex); 2093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); 2103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r2, Operand(Smi::FromInt(length))); 2113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r2, FieldMemOperand(r0, FixedArray::kLengthOffset)); 2123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // If this block context is nested in the global context we get a smi 2143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // sentinel instead of a function. The block context should get the 2153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // canonical empty function of the global context as its closure which 2163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // we still have to look up. 2173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label after_sentinel; 2183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfNotSmi(r3, &after_sentinel); 2193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (FLAG_debug_code) { 2203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const char* message = "Expected 0 as a Smi sentinel"; 2213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(r3, Operand::Zero()); 2223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Assert(eq, message); 2233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r3, GlobalObjectOperand()); 2253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r3, FieldMemOperand(r3, GlobalObject::kGlobalContextOffset)); 2263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r3, ContextOperand(r3, Context::CLOSURE_INDEX)); 2273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&after_sentinel); 2283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up the fixed slots, copy the global object from the previous context. 2303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r2, ContextOperand(cp, Context::GLOBAL_INDEX)); 2313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r3, ContextOperand(r0, Context::CLOSURE_INDEX)); 2323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(cp, ContextOperand(r0, Context::PREVIOUS_INDEX)); 2333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r1, ContextOperand(r0, Context::EXTENSION_INDEX)); 2343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r2, ContextOperand(r0, Context::GLOBAL_INDEX)); 2353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Initialize the rest of the slots to the hole value. 2373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ LoadRoot(r1, Heap::kTheHoleValueRootIndex); 2383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = 0; i < slots_; i++) { 2393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r1, ContextOperand(r0, i + Context::MIN_CONTEXT_SLOTS)); 2403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Remove the on-stack argument and return. 2433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(cp, r0); 2443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(sp, sp, Operand(2 * kPointerSize)); 2453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(); 2463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Need to collect. Call into runtime system. 2483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&gc); 2493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kPushBlockContext, 2, 1); 2503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 2513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic void GenerateFastCloneShallowArrayCommon( 2543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler* masm, 2553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int length, 2563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FastCloneShallowArrayStub::Mode mode, 2573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label* fail) { 2583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Registers on entry: 2593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // 2603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r3: boilerplate literal array. 2613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS); 2623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // All sizes here are multiples of kPointerSize. 2643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int elements_size = 0; 2653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (length > 0) { 2663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS 2673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ? FixedDoubleArray::SizeFor(length) 2683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch : FixedArray::SizeFor(length); 2693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int size = JSArray::kSize + elements_size; 2713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Allocate both the JS array and the elements array in one big 2733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // allocation. This avoids multiple limit checks. 2743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateInNewSpace(size, 2753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r0, 2763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r1, 2773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r2, 2783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch fail, 2793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch TAG_OBJECT); 2803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Copy the JS array part. 2823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = 0; i < JSArray::kSize; i += kPointerSize) { 2833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if ((i != JSArray::kElementsOffset) || (length == 0)) { 2843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r1, FieldMemOperand(r3, i)); 2853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r1, FieldMemOperand(r0, i)); 2863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (length > 0) { 2903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Get hold of the elements array of the boilerplate and setup the 2913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // elements pointer in the resulting object. 2923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r3, FieldMemOperand(r3, JSArray::kElementsOffset)); 2933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r2, r0, Operand(JSArray::kSize)); 2943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r2, FieldMemOperand(r0, JSArray::kElementsOffset)); 2953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Copy the elements array. 2973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT((elements_size % kPointerSize) == 0); 2983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CopyFields(r2, r3, r1.bit(), elements_size / kPointerSize); 2993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 3003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 3013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 30280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { 30380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack layout on entry: 30480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // 30580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // [sp]: constant elements. 30680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // [sp + kPointerSize]: literal index. 30780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // [sp + (2 * kPointerSize)]: literals array. 30880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 30980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load boilerplate object into r3 and check if we need to create a 31080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // boilerplate. 31180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow_case; 31280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, MemOperand(sp, 2 * kPointerSize)); 31380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); 31480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r3, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 31580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize)); 3163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(r3, Heap::kUndefinedValueRootIndex); 31780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &slow_case); 31880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FastCloneShallowArrayStub::Mode mode = mode_; 3203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (mode == CLONE_ANY_ELEMENTS) { 3213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label double_elements, check_fast_elements; 3223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r0, FieldMemOperand(r3, JSArray::kElementsOffset)); 3233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); 3243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(r0, Heap::kFixedCOWArrayMapRootIndex); 3253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &check_fast_elements); 3263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateFastCloneShallowArrayCommon(masm, 0, 3273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch COPY_ON_WRITE_ELEMENTS, &slow_case); 3283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Return and remove the on-stack parameters. 3293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(sp, sp, Operand(3 * kPointerSize)); 3303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(); 3313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 3323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&check_fast_elements); 3333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(r0, Heap::kFixedArrayMapRootIndex); 3343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &double_elements); 3353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateFastCloneShallowArrayCommon(masm, length_, 3363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CLONE_ELEMENTS, &slow_case); 3373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Return and remove the on-stack parameters. 3383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(sp, sp, Operand(3 * kPointerSize)); 3393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(); 3403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 3413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&double_elements); 3423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch mode = CLONE_DOUBLE_ELEMENTS; 3433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Fall through to generate the code to handle double elements. 3443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 3453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 34680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 34780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const char* message; 34880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Heap::RootListIndex expected_map_index; 3493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (mode == CLONE_ELEMENTS) { 35080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen message = "Expected (writable) fixed array"; 35180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen expected_map_index = Heap::kFixedArrayMapRootIndex; 3523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else if (mode == CLONE_DOUBLE_ELEMENTS) { 3533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch message = "Expected (writable) fixed double array"; 3543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch expected_map_index = Heap::kFixedDoubleArrayMapRootIndex; 35580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 3563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(mode == COPY_ON_WRITE_ELEMENTS); 35780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen message = "Expected copy-on-write fixed array"; 35880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen expected_map_index = Heap::kFixedCOWArrayMapRootIndex; 35980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 36080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(r3); 36180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, FieldMemOperand(r3, JSArray::kElementsOffset)); 36280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); 3633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(r3, expected_map_index); 36480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Assert(eq, message); 36580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(r3); 36680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 36780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateFastCloneShallowArrayCommon(masm, length_, mode, &slow_case); 369592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch 3703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Return and remove the on-stack parameters. 3713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(sp, sp, Operand(3 * kPointerSize)); 3723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(); 373592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch 3743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&slow_case); 3753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); 3763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 377592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch 3783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 3793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid FastCloneShallowObjectStub::Generate(MacroAssembler* masm) { 3803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Stack layout on entry: 3813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // 3823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // [sp]: object literal flags. 3833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // [sp + kPointerSize]: constant properties. 3843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // [sp + (2 * kPointerSize)]: literal index. 3853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // [sp + (3 * kPointerSize)]: literals array. 3863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 3873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load boilerplate object into r3 and check if we need to create a 3883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // boilerplate. 3893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label slow_case; 3903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r3, MemOperand(sp, 3 * kPointerSize)); 3913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r0, MemOperand(sp, 2 * kPointerSize)); 3923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r3, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 3933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r3, MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize)); 3943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(r3, Heap::kUndefinedValueRootIndex); 3953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &slow_case); 3963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 3973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Check that the boilerplate contains only fast properties and we can 3983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // statically determine the instance size. 3993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int size = JSObject::kHeaderSize + length_ * kPointerSize; 4003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r0, FieldMemOperand(r3, HeapObject::kMapOffset)); 4013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceSizeOffset)); 4023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(r0, Operand(size >> kPointerSizeLog2)); 4033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &slow_case); 4043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 4053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Allocate the JS object and copy header together with all in-object 4063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // properties from the boilerplate. 4073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateInNewSpace(size, r0, r1, r2, &slow_case, TAG_OBJECT); 4083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = 0; i < size; i += kPointerSize) { 4093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r1, FieldMemOperand(r3, i)); 4103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r1, FieldMemOperand(r0, i)); 41180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 41280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 41380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameters. 4143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(sp, sp, Operand(4 * kPointerSize)); 41580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 41680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 41780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow_case); 4183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kCreateObjectLiteralShallow, 4, 1); 41980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 42080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 42180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 42280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Takes a Smi and converts to an IEEE 64 bit floating point value in two 42380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// registers. The format is 1 sign bit, 11 exponent bits (biased 1023) and 42480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// 52 fraction bits (20 in the first word, 32 in the second). Zeros is a 42580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// scratch register. Destroys the source register. No GC occurs during this 42680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// stub so you don't have to set up the frame. 42780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenclass ConvertToDoubleStub : public CodeStub { 42880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen public: 42980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ConvertToDoubleStub(Register result_reg_1, 43080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register result_reg_2, 43180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register source_reg, 43280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch_reg) 43380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen : result1_(result_reg_1), 43480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen result2_(result_reg_2), 43580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen source_(source_reg), 43680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen zeros_(scratch_reg) { } 43780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 43880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen private: 43980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register result1_; 44080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register result2_; 44180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register source_; 44280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register zeros_; 44380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 44480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Minor key encoding in 16 bits. 44580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen class ModeBits: public BitField<OverwriteMode, 0, 2> {}; 44680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen class OpBits: public BitField<Token::Value, 2, 14> {}; 44780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 44880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Major MajorKey() { return ConvertToDouble; } 44980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int MinorKey() { 45080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Encode the parameters in a unique 16 bit value. 45180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return result1_.code() + 45280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen (result2_.code() << 4) + 45380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen (source_.code() << 8) + 45480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen (zeros_.code() << 12); 45580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 45680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 45780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen void Generate(MacroAssembler* masm); 45880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}; 45980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 46080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 46180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ConvertToDoubleStub::Generate(MacroAssembler* masm) { 46280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register exponent = result1_; 46380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register mantissa = result2_; 4648b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch 46580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label not_special; 46680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Convert from Smi to integer. 46780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(source_, Operand(source_, ASR, kSmiTagSize)); 46880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Move sign bit from source to destination. This works because the sign bit 46980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // in the exponent word of the double has the same position and polarity as 47080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the 2's complement sign bit in a Smi. 47180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u); 47280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(exponent, source_, Operand(HeapNumber::kSignMask), SetCC); 47380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Subtract from 0 if source was negative. 4749ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ rsb(source_, source_, Operand(0, RelocInfo::NONE), LeaveCC, ne); 47580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 47680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We have -1, 0 or 1, which we treat specially. Register source_ contains 47780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // absolute value: it is either equal to 1 (special case of -1 and 1), 47880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // greater than 1 (not a special case) or less than 1 (special case of 0). 47980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(source_, Operand(1)); 48080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(gt, ¬_special); 48180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 48280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // For 1 or -1 we need to or in the 0 exponent (biased to 1023). 4833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const uint32_t exponent_word_for_1 = 48480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen HeapNumber::kExponentBias << HeapNumber::kExponentShift; 48580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ orr(exponent, exponent, Operand(exponent_word_for_1), LeaveCC, eq); 48680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // 1, 0 and -1 all have 0 for the second word. 4879ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(mantissa, Operand(0, RelocInfo::NONE)); 48880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 48980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 49080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_special); 49180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Count leading zeros. Uses mantissa for a scratch register on pre-ARM5. 49280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Gets the wrong answer for 0, but we already checked for that case above. 49380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CountLeadingZeros(zeros_, source_, mantissa); 49480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compute exponent and or it into the exponent register. 49580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We use mantissa as a scratch register here. Use a fudge factor to 49680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // divide the constant 31 + HeapNumber::kExponentBias, 0x41d, into two parts 49780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // that fit in the ARM's constant field. 49880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int fudge = 0x400; 49980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ rsb(mantissa, zeros_, Operand(31 + HeapNumber::kExponentBias - fudge)); 50080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(mantissa, mantissa, Operand(fudge)); 50180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ orr(exponent, 50280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen exponent, 50380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Operand(mantissa, LSL, HeapNumber::kExponentShift)); 50480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Shift up the source chopping the top bit off. 50580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(zeros_, zeros_, Operand(1)); 50680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // This wouldn't work for 1.0 or -1.0 as the shift would be 32 which means 0. 50780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(source_, Operand(source_, LSL, zeros_)); 50880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compute lower part of fraction (last 12 bits). 50980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(mantissa, Operand(source_, LSL, HeapNumber::kMantissaBitsInTopWord)); 51080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // And the top (top 20 bits). 51180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ orr(exponent, 51280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen exponent, 51380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Operand(source_, LSR, 32 - HeapNumber::kMantissaBitsInTopWord)); 51480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 51580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 51680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 51780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid FloatingPointHelper::LoadSmis(MacroAssembler* masm, 5191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block FloatingPointHelper::Destination destination, 5201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch1, 5211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch2) { 5228b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 5231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block CpuFeatures::Scope scope(VFP3); 5241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(scratch1, Operand(r0, ASR, kSmiTagSize)); 5251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vmov(d7.high(), scratch1); 5261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vcvt_f64_s32(d7, d7.high()); 5271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(scratch1, Operand(r1, ASR, kSmiTagSize)); 5281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vmov(d6.high(), scratch1); 5291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vcvt_f64_s32(d6, d6.high()); 5301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (destination == kCoreRegisters) { 5311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vmov(r2, r3, d7); 5321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vmov(r0, r1, d6); 5331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 5341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 5351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(destination == kCoreRegisters); 5361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Write Smi from r0 to r3 and r2 in double format. 5371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(scratch1, Operand(r0)); 5381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ConvertToDoubleStub stub1(r3, r2, scratch1, scratch2); 5391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(lr); 5403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Call(stub1.GetCode()); 5418b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Write Smi from r1 to r1 and r0 in double format. 5421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(scratch1, Operand(r1)); 5431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ConvertToDoubleStub stub2(r1, r0, scratch1, scratch2); 5443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Call(stub2.GetCode()); 5451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ pop(lr); 5461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 5471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 5481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 5491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 5501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid FloatingPointHelper::LoadOperands( 5511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block MacroAssembler* masm, 5521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block FloatingPointHelper::Destination destination, 5531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register heap_number_map, 5541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch1, 5551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch2, 5561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label* slow) { 5571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 5581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Load right operand (r0) to d6 or r2/r3. 5591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block LoadNumber(masm, destination, 5601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block r0, d7, r2, r3, heap_number_map, scratch1, scratch2, slow); 5611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 5621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Load left operand (r1) to d7 or r0/r1. 5631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block LoadNumber(masm, destination, 5641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block r1, d6, r0, r1, heap_number_map, scratch1, scratch2, slow); 5651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 5661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 5671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 5681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid FloatingPointHelper::LoadNumber(MacroAssembler* masm, 5691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Destination destination, 5701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register object, 5711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block DwVfpRegister dst, 5721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register dst1, 5731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register dst2, 5741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register heap_number_map, 5751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch1, 5761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch2, 5771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label* not_number) { 5781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (FLAG_debug_code) { 5791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ AbortIfNotRootValue(heap_number_map, 5801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Heap::kHeapNumberMapRootIndex, 5811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block "HeapNumberMap register clobbered."); 5821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 5831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 5841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label is_smi, done; 5851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 5863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Smi-check 5873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ UntagAndJumpIfSmi(scratch1, object, &is_smi); 5883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Heap number check 5891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); 5901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 5911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Handle loading a double from a heap number. 5928b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3) && 59344f0eee88ff00398ff7f715fab053374d808c90dSteve Block destination == kVFPRegisters) { 5941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block CpuFeatures::Scope scope(VFP3); 5951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Load the double from tagged HeapNumber to double register. 5961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ sub(scratch1, object, Operand(kHeapObjectTag)); 5971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vldr(dst, scratch1, HeapNumber::kValueOffset); 5981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 5991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(destination == kCoreRegisters); 6001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Load the double from heap number to dst1 and dst2 in double format. 6011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ldrd(dst1, dst2, FieldMemOperand(object, HeapNumber::kValueOffset)); 6021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 6031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ jmp(&done); 6041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 6051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Handle loading a double from a smi. 6061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&is_smi); 6078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 6081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block CpuFeatures::Scope scope(VFP3); 6091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Convert smi to double using VFP instructions. 6101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vmov(dst.high(), scratch1); 6111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vcvt_f64_s32(dst, dst.high()); 6121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (destination == kCoreRegisters) { 6131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Load the converted smi to dst1 and dst2 in double format. 6141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vmov(dst1, dst2, dst); 6151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 6161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 6171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(destination == kCoreRegisters); 6181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Write smi to dst1 and dst2 double format. 6191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(scratch1, Operand(object)); 6201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2); 6211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(lr); 6223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Call(stub.GetCode()); 6231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ pop(lr); 6241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 6251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 6261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&done); 6271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 6281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 6291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 63044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid FloatingPointHelper::ConvertNumberToInt32(MacroAssembler* masm, 63144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Register object, 63244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Register dst, 63344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Register heap_number_map, 63444f0eee88ff00398ff7f715fab053374d808c90dSteve Block Register scratch1, 63544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Register scratch2, 63644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Register scratch3, 63744f0eee88ff00398ff7f715fab053374d808c90dSteve Block DwVfpRegister double_scratch, 63844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Label* not_number) { 6391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (FLAG_debug_code) { 6401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ AbortIfNotRootValue(heap_number_map, 6411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Heap::kHeapNumberMapRootIndex, 6421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block "HeapNumberMap register clobbered."); 6431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 64444f0eee88ff00398ff7f715fab053374d808c90dSteve Block Label done; 64544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Label not_in_int32_range; 64644f0eee88ff00398ff7f715fab053374d808c90dSteve Block 6473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ UntagAndJumpIfSmi(dst, object, &done); 6481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kMapOffset)); 6491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ cmp(scratch1, heap_number_map); 65044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ b(ne, not_number); 65144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ ConvertToInt32(object, 65244f0eee88ff00398ff7f715fab053374d808c90dSteve Block dst, 65344f0eee88ff00398ff7f715fab053374d808c90dSteve Block scratch1, 65444f0eee88ff00398ff7f715fab053374d808c90dSteve Block scratch2, 65544f0eee88ff00398ff7f715fab053374d808c90dSteve Block double_scratch, 65644f0eee88ff00398ff7f715fab053374d808c90dSteve Block ¬_in_int32_range); 6571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ jmp(&done); 65844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 65944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(¬_in_int32_range); 66044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset)); 66144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ ldr(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset)); 66244f0eee88ff00398ff7f715fab053374d808c90dSteve Block 66344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ EmitOutOfInt32RangeTruncate(dst, 66444f0eee88ff00398ff7f715fab053374d808c90dSteve Block scratch1, 66544f0eee88ff00398ff7f715fab053374d808c90dSteve Block scratch2, 66644f0eee88ff00398ff7f715fab053374d808c90dSteve Block scratch3); 6671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&done); 6681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 6691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 6701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid FloatingPointHelper::ConvertIntToDouble(MacroAssembler* masm, 672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register int_scratch, 673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Destination destination, 674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch DwVfpRegister double_dst, 675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register dst1, 676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register dst2, 677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch2, 678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch SwVfpRegister single_scratch) { 679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(!int_scratch.is(scratch2)); 680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(!int_scratch.is(dst1)); 681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(!int_scratch.is(dst2)); 682e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done; 684e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 6858b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 686e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch CpuFeatures::Scope scope(VFP3); 687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ vmov(single_scratch, int_scratch); 688e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vcvt_f64_s32(double_dst, single_scratch); 689e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (destination == kCoreRegisters) { 690e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vmov(dst1, dst2, double_dst); 691e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 692e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { 693e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label fewer_than_20_useful_bits; 694e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Expected output: 6958b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // | dst2 | dst1 | 696e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // | s | exp | mantissa | 697e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 698e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Check for zero. 69969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(int_scratch, Operand::Zero()); 700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(dst2, int_scratch); 701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(dst1, int_scratch); 702e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(eq, &done); 703e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 704e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Preload the sign of the value. 705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(dst2, int_scratch, Operand(HeapNumber::kSignMask), SetCC); 706e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Get the absolute value of the object (as an unsigned integer). 70769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ rsb(int_scratch, int_scratch, Operand::Zero(), SetCC, mi); 708e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 7093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Get mantissa[51:20]. 710e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 711e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Get the position of the first set bit. 712257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CountLeadingZeros(dst1, int_scratch, scratch2); 7138b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ rsb(dst1, dst1, Operand(31)); 714e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 715e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Set the exponent. 7168b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ add(scratch2, dst1, Operand(HeapNumber::kExponentBias)); 7178b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ Bfi(dst2, scratch2, scratch2, 718e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch HeapNumber::kExponentShift, HeapNumber::kExponentBits); 719e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 720e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Clear the first non null bit. 721e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(scratch2, Operand(1)); 722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bic(int_scratch, int_scratch, Operand(scratch2, LSL, dst1)); 723e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 7248b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ cmp(dst1, Operand(HeapNumber::kMantissaBitsInTopWord)); 725e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Get the number of bits to set in the lower part of the mantissa. 7268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ sub(scratch2, dst1, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC); 727e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(mi, &fewer_than_20_useful_bits); 728e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Set the higher 20 bits of the mantissa. 729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ orr(dst2, dst2, Operand(int_scratch, LSR, scratch2)); 730e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ rsb(scratch2, scratch2, Operand(32)); 731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(dst1, Operand(int_scratch, LSL, scratch2)); 732e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(&done); 733e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 734e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&fewer_than_20_useful_bits); 7358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ rsb(scratch2, dst1, Operand(HeapNumber::kMantissaBitsInTopWord)); 736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch2, Operand(int_scratch, LSL, scratch2)); 7378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ orr(dst2, dst2, scratch2); 7388b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Set dst1 to 0. 73969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(dst1, Operand::Zero()); 740e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 741257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&done); 742257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 743257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 745257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm, 746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register object, 747257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Destination destination, 748257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch DwVfpRegister double_dst, 749257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register dst1, 750257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register dst2, 751257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register heap_number_map, 752257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch1, 753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch2, 754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch SwVfpRegister single_scratch, 755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* not_int32) { 756257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(!scratch1.is(object) && !scratch2.is(object)); 757257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(!scratch1.is(scratch2)); 758257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(!heap_number_map.is(object) && 759257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch !heap_number_map.is(scratch1) && 760257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch !heap_number_map.is(scratch2)); 761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label done, obj_is_not_smi; 763e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 764257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfNotSmi(object, &obj_is_not_smi); 765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiUntag(scratch1, object); 766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ConvertIntToDouble(masm, scratch1, destination, double_dst, dst1, dst2, 767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch scratch2, single_scratch); 768e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(&done); 769e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 770e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&obj_is_not_smi); 771e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (FLAG_debug_code) { 772e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ AbortIfNotRootValue(heap_number_map, 773e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Heap::kHeapNumberMapRootIndex, 774e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch "HeapNumberMap register clobbered."); 775e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 776e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32); 777e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 778e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Load the number. 7798b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 780e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch CpuFeatures::Scope scope(VFP3); 781e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Load the double value. 782e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ sub(scratch1, object, Operand(kHeapObjectTag)); 783e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vldr(double_dst, scratch1, HeapNumber::kValueOffset); 784e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 785e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ EmitVFPTruncate(kRoundToZero, 786e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch single_scratch, 787e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch double_dst, 788e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch1, 789e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch2, 790e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch kCheckForInexactConversion); 791e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 792e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Jump to not_int32 if the operation did not succeed. 793e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(ne, not_int32); 794e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 795e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (destination == kCoreRegisters) { 796e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vmov(dst1, dst2, double_dst); 797e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 798e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 799e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { 800e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ASSERT(!scratch1.is(object) && !scratch2.is(object)); 801e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Load the double value in the destination registers.. 802e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ldrd(dst1, dst2, FieldMemOperand(object, HeapNumber::kValueOffset)); 803e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 804e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Check for 0 and -0. 805e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bic(scratch1, dst1, Operand(HeapNumber::kSignMask)); 806e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ orr(scratch1, scratch1, Operand(dst2)); 80769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(scratch1, Operand::Zero()); 808e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(eq, &done); 809e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 810e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Check that the value can be exactly represented by a 32-bit integer. 811e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Jump to not_int32 if that's not the case. 812e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch DoubleIs32BitInteger(masm, dst1, dst2, scratch1, scratch2, not_int32); 813e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 814e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // dst1 and dst2 were trashed. Reload the double value. 815e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ldrd(dst1, dst2, FieldMemOperand(object, HeapNumber::kValueOffset)); 816e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 817e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 818e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&done); 819e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch} 820e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 821e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 822e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm, 823e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register object, 824e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register dst, 825e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register heap_number_map, 826e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch1, 827e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch2, 828e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch3, 829e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch DwVfpRegister double_scratch, 830e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label* not_int32) { 831e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ASSERT(!dst.is(object)); 832e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ASSERT(!scratch1.is(object) && !scratch2.is(object) && !scratch3.is(object)); 833e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ASSERT(!scratch1.is(scratch2) && 834e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch !scratch1.is(scratch3) && 835e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch !scratch2.is(scratch3)); 836e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 837e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label done; 838e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 8393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ UntagAndJumpIfSmi(dst, object, &done); 840e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 841e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (FLAG_debug_code) { 842e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ AbortIfNotRootValue(heap_number_map, 843e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Heap::kHeapNumberMapRootIndex, 844e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch "HeapNumberMap register clobbered."); 845e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 846e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32); 847e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 848e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Object is a heap number. 849e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Convert the floating point value to a 32-bit integer. 8508b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 851e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch CpuFeatures::Scope scope(VFP3); 852e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch SwVfpRegister single_scratch = double_scratch.low(); 853e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Load the double value. 854e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ sub(scratch1, object, Operand(kHeapObjectTag)); 855e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vldr(double_scratch, scratch1, HeapNumber::kValueOffset); 856e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 857e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ EmitVFPTruncate(kRoundToZero, 858e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch single_scratch, 859e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch double_scratch, 860e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch1, 861e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch2, 862e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch kCheckForInexactConversion); 863e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 864e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Jump to not_int32 if the operation did not succeed. 865e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(ne, not_int32); 866e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Get the result in the destination register. 867e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vmov(dst, single_scratch); 868e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 869e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { 870e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Load the double value in the destination registers. 871e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset)); 872e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ldr(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset)); 873e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 874e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Check for 0 and -0. 875e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bic(dst, scratch1, Operand(HeapNumber::kSignMask)); 876e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ orr(dst, scratch2, Operand(dst)); 87769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(dst, Operand::Zero()); 878e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(eq, &done); 879e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 880e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch DoubleIs32BitInteger(masm, scratch1, scratch2, dst, scratch3, not_int32); 881e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 882e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Registers state after DoubleIs32BitInteger. 883e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // dst: mantissa[51:20]. 884e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // scratch2: 1 885e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 886e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Shift back the higher bits of the mantissa. 887e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(dst, Operand(dst, LSR, scratch3)); 888e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Set the implicit first bit. 889e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ rsb(scratch3, scratch3, Operand(32)); 890e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ orr(dst, dst, Operand(scratch2, LSL, scratch3)); 891e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Set the sign. 892e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset)); 893e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ tst(scratch1, Operand(HeapNumber::kSignMask)); 89469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ rsb(dst, dst, Operand::Zero(), LeaveCC, mi); 895e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 896e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 897e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&done); 898e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch} 899e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 900e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 901e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm, 902e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register src1, 903e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register src2, 904e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register dst, 905e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch, 906e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label* not_int32) { 907e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Get exponent alone in scratch. 908e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ubfx(scratch, 909e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch src1, 910e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch HeapNumber::kExponentShift, 911e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch HeapNumber::kExponentBits); 912e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 913e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Substract the bias from the exponent. 914e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ sub(scratch, scratch, Operand(HeapNumber::kExponentBias), SetCC); 915e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 916e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // src1: higher (exponent) part of the double value. 917e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // src2: lower (mantissa) part of the double value. 918e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // scratch: unbiased exponent. 919e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 920e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Fast cases. Check for obvious non 32-bit integer values. 921e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Negative exponent cannot yield 32-bit integers. 922e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(mi, not_int32); 923e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Exponent greater than 31 cannot yield 32-bit integers. 924e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Also, a positive value with an exponent equal to 31 is outside of the 925e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // signed 32-bit integer range. 926e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Another way to put it is that if (exponent - signbit) > 30 then the 927e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // number cannot be represented as an int32. 928e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register tmp = dst; 929e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ sub(tmp, scratch, Operand(src1, LSR, 31)); 930e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cmp(tmp, Operand(30)); 931e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(gt, not_int32); 932e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // - Bits [21:0] in the mantissa are not null. 933e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ tst(src2, Operand(0x3fffff)); 934e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(ne, not_int32); 935e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 936e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Otherwise the exponent needs to be big enough to shift left all the 937e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // non zero bits left. So we need the (30 - exponent) last bits of the 938e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // 31 higher bits of the mantissa to be null. 939e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Because bits [21:0] are null, we can check instead that the 9403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // (32 - exponent) last bits of the 32 higher bits of the mantissa are null. 941e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 942e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Get the 32 higher bits of the mantissa in dst. 943e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ubfx(dst, 944e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch src2, 945e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch HeapNumber::kMantissaBitsInTopWord, 946e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 32 - HeapNumber::kMantissaBitsInTopWord); 947e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ orr(dst, 948e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch dst, 949e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Operand(src1, LSL, HeapNumber::kNonMantissaBitsInTopWord)); 950e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 951e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Create the mask and test the lower bits (of the higher bits). 952e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ rsb(scratch, scratch, Operand(32)); 953e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(src2, Operand(1)); 954e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(src1, Operand(src2, LSL, scratch)); 955e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ sub(src1, src1, Operand(1)); 956e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ tst(dst, src1); 957e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(ne, not_int32); 958e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch} 959e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 960e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 961e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid FloatingPointHelper::CallCCodeForDoubleOperation( 962e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch MacroAssembler* masm, 963e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Token::Value op, 964e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register heap_number_result, 965e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch) { 966e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Using core registers: 967e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // r0: Left value (least significant part of mantissa). 968e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // r1: Left value (sign, exponent, top of mantissa). 969e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // r2: Right value (least significant part of mantissa). 970e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // r3: Right value (sign, exponent, top of mantissa). 971e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 972e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Assert that heap_number_result is callee-saved. 973e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // We currently always use r5 to pass it. 974e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ASSERT(heap_number_result.is(r5)); 975e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 976e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Push the current return address before the C call. Return will be 977e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // through pop(pc) below. 978e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ push(lr); 979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ PrepareCallCFunction(0, 2, scratch); 980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (masm->use_eabi_hardfloat()) { 981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CpuFeatures::Scope scope(VFP3); 982257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ vmov(d0, r0, r1); 983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ vmov(d1, r2, r3); 984257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 9853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 9863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch AllowExternalCallThatCantCauseGC scope(masm); 9873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallCFunction( 9883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference::double_fp_operation(op, masm->isolate()), 0, 2); 9893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 9908b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // Store answer in the overwritable heap number. Double returned in 991257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // registers r0 and r1 or in d0. 992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (masm->use_eabi_hardfloat()) { 993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CpuFeatures::Scope scope(VFP3); 994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ vstr(d0, 995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch FieldMemOperand(heap_number_result, HeapNumber::kValueOffset)); 996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Strd(r0, r1, FieldMemOperand(heap_number_result, 998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch HeapNumber::kValueOffset)); 999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 1000e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Place heap_number_result in r0 and return to the pushed return address. 1001e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(r0, Operand(heap_number_result)); 1002e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ pop(pc); 1003e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch} 1004e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 10051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 10063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool WriteInt32ToHeapNumberStub::IsPregenerated() { 10073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // These variants are compiled ahead of time. See next method. 10083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (the_int_.is(r1) && the_heap_number_.is(r0) && scratch_.is(r2)) { 10093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return true; 10103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 10113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (the_int_.is(r2) && the_heap_number_.is(r0) && scratch_.is(r3)) { 10123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return true; 10133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 10143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Other register combinations are generated as and when they are needed, 10153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // so it is unsafe to call them from stubs (we can't generate a stub while 10163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // we are generating a stub). 10173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return false; 10183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 10193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 10203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 10213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime() { 10223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch WriteInt32ToHeapNumberStub stub1(r1, r0, r2); 10233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch WriteInt32ToHeapNumberStub stub2(r2, r0, r3); 10243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch stub1.GetCode()->set_is_pregenerated(true); 10253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch stub2.GetCode()->set_is_pregenerated(true); 10263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 10273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 10283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 102980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// See comment for class. 103080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) { 103180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label max_negative_int; 103280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the_int_ has the answer which is a signed int32 but not a Smi. 103380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We test for the special value that has a different exponent. This test 103480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // has the neat side effect of setting the flags according to the sign. 103580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u); 103680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(the_int_, Operand(0x80000000u)); 103780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &max_negative_int); 103880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Set up the correct exponent in scratch_. All non-Smi int32s have the same. 103980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). 104080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen uint32_t non_smi_exponent = 104180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; 104280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch_, Operand(non_smi_exponent)); 104380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Set the sign bit in scratch_ if the value was negative. 104480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ orr(scratch_, scratch_, Operand(HeapNumber::kSignMask), LeaveCC, cs); 104580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Subtract from 0 if the value was negative. 10469ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ rsb(the_int_, the_int_, Operand(0, RelocInfo::NONE), LeaveCC, cs); 104780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We should be masking the implict first digit of the mantissa away here, 104880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // but it just ends up combining harmlessly with the last digit of the 104980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // exponent that happens to be 1. The sign bit is 0 so we shift 10 to get 105080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the most significant 1 to hit the last bit of the 12 bit sign and exponent. 105180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(((1 << HeapNumber::kExponentShift) & non_smi_exponent) != 0); 105280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2; 105380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ orr(scratch_, scratch_, Operand(the_int_, LSR, shift_distance)); 105480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(scratch_, FieldMemOperand(the_heap_number_, 105580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen HeapNumber::kExponentOffset)); 105680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch_, Operand(the_int_, LSL, 32 - shift_distance)); 105780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(scratch_, FieldMemOperand(the_heap_number_, 105880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen HeapNumber::kMantissaOffset)); 105980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 106080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 106180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&max_negative_int); 106280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The max negative int32 is stored as a positive number in the mantissa of 106380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // a double because it uses a sign bit instead of using two's complement. 106480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The actual mantissa bits stored are all 0 because the implicit most 106580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // significant 1 bit is not stored. 106680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen non_smi_exponent += 1 << HeapNumber::kExponentShift; 106780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ip, Operand(HeapNumber::kSignMask | non_smi_exponent)); 106880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kExponentOffset)); 10699ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(ip, Operand(0, RelocInfo::NONE)); 107080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset)); 107180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 107280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 107380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 107480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 107580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Handle the case where the lhs and rhs are the same object. 107680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Equality is almost reflexive (everything but NaN), so this is a test 107780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// for "identity and not NaN". 107880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic void EmitIdenticalObjectComparison(MacroAssembler* masm, 107980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* slow, 10801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Condition cond, 108180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool never_nan_nan) { 108280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label not_identical; 108380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label heap_number, return_equal; 108480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r0, r1); 108580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, ¬_identical); 108680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 108780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The two objects are identical. If we know that one of them isn't NaN then 108880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // we now know they test equal. 10891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (cond != eq || !never_nan_nan) { 109044f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(), 109180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // so we do the second best thing - test it ourselves. 109280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // They are both equal and they are not both Smis so both of them are not 109380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Smis. If it's not a heap number, then return equal. 10941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (cond == lt || cond == gt) { 10953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE); 109680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ge, slow); 109780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 109880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE); 109980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &heap_number); 110080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Comparing JS objects with <=, >= is complicated. 11011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (cond != eq) { 11023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE)); 110380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ge, slow); 110480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Normally here we fall through to return_equal, but undefined is 110580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // special: (undefined == undefined) == true, but 110680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // (undefined <= undefined) == false! See ECMAScript 11.8.5. 11071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (cond == le || cond == ge) { 110880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r4, Operand(ODDBALL_TYPE)); 110980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &return_equal); 111080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); 111180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r0, r2); 111280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &return_equal); 11131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (cond == le) { 111480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // undefined <= undefined should fail. 111580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(GREATER)); 111680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 111780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // undefined >= undefined should fail. 111880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(LESS)); 111980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 112080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 112180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 112280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 112380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 112480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 112580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 112680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&return_equal); 11271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (cond == lt) { 112880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(GREATER)); // Things aren't less than themselves. 11291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else if (cond == gt) { 113080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(LESS)); // Things aren't greater than themselves. 113180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 113280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(EQUAL)); // Things are <=, >=, ==, === themselves. 113380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 113480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 113580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 11361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (cond != eq || !never_nan_nan) { 113780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // For less and greater we don't have to check for NaN since the result of 113880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // x < x is false regardless. For the others here is some code to check 113980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // for NaN. 11401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (cond != lt && cond != gt) { 114180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&heap_number); 114280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // It is a heap number, so return non-equal if it's NaN and equal if it's 114380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // not NaN. 114480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 114580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The representation of NaN values has all exponent bits (52..62) set, 114680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and not all mantissa bits (0..51) clear. 114780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read top bits of double representation (second word of value). 114880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); 114980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Test that exponent bits are all set. 115080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Sbfx(r3, r2, HeapNumber::kExponentShift, HeapNumber::kExponentBits); 115180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NaNs have all-one exponents so they sign extend to -1. 115280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r3, Operand(-1)); 115380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &return_equal); 115480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 115580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Shift out flag and all exponent bits, retaining only mantissa. 115680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord)); 115780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Or with all low-bits of mantissa. 115880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); 115980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ orr(r0, r3, Operand(r2), SetCC); 116080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // For equal we already have the right value in r0: Return zero (equal) 116180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // if all bits in mantissa are zero (it's an Infinity) and non-zero if 116280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // not (it's a NaN). For <= and >= we need to load r0 with the failing 116380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // value if it's a NaN. 11641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (cond != eq) { 116580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // All-zero means Infinity means equal. 116680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(eq); 11671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (cond == le) { 116880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail. 116980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 117080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(LESS)); // NaN >= NaN should fail. 117180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 117280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 117380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 117480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 117580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // No fall through here. 117680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 117780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 117880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_identical); 117980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 118080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 118180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 118280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// See comment at call site. 118380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic void EmitSmiNonsmiComparison(MacroAssembler* masm, 118480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register lhs, 118580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register rhs, 118680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* lhs_not_nan, 118780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* slow, 118880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool strict) { 118980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT((lhs.is(r0) && rhs.is(r1)) || 119080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen (lhs.is(r1) && rhs.is(r0))); 119180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 119280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label rhs_is_smi; 11933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(rhs, &rhs_is_smi); 119480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 119580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Lhs is a Smi. Check whether the rhs is a heap number. 119680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareObjectType(rhs, r4, r4, HEAP_NUMBER_TYPE); 119780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (strict) { 119880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If rhs is not a number and lhs is a Smi then strict equality cannot 119980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // succeed. Return non-equal 120080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If rhs is r0 then there is already a non zero value in it. 120180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!rhs.is(r0)) { 120280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne); 120380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 120480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(ne); 120580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 120680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Smi compared non-strictly with a non-Smi non-heap-number. Call 120780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the runtime. 120880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, slow); 120980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 121080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 121180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Lhs is a smi, rhs is a number. 12128b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 121380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Convert lhs to a double in d7. 121480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope scope(VFP3); 121580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToDoubleVFPRegister(lhs, d7, r7, s15); 121680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the double from rhs, tagged HeapNumber r0, to d6. 121780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(r7, rhs, Operand(kHeapObjectTag)); 121880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ vldr(d6, r7, HeapNumber::kValueOffset); 121980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 122080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(lr); 122180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Convert lhs to a double in r2, r3. 122280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r7, Operand(lhs)); 122380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ConvertToDoubleStub stub1(r3, r2, r7, r6); 12243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Call(stub1.GetCode()); 122580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load rhs to a double in r0, r1. 122680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset)); 122780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(lr); 122880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 122980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 123080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We now have both loaded as doubles but we can skip the lhs nan check 123180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // since it's a smi. 123280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(lhs_not_nan); 123380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 123480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&rhs_is_smi); 123580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Rhs is a smi. Check whether the non-smi lhs is a heap number. 123680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareObjectType(lhs, r4, r4, HEAP_NUMBER_TYPE); 123780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (strict) { 123880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If lhs is not a number and rhs is a smi then strict equality cannot 123980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // succeed. Return non-equal. 124080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If lhs is r0 then there is already a non zero value in it. 124180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!lhs.is(r0)) { 124280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne); 124380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 124480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(ne); 124580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 124680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Smi compared non-strictly with a non-smi non-heap-number. Call 124780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the runtime. 124880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, slow); 124980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 125080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 125180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Rhs is a smi, lhs is a heap number. 12528b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 125380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope scope(VFP3); 125480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the double from lhs, tagged HeapNumber r1, to d7. 125580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(r7, lhs, Operand(kHeapObjectTag)); 125680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ vldr(d7, r7, HeapNumber::kValueOffset); 125780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Convert rhs to a double in d6 . 125880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ SmiToDoubleVFPRegister(rhs, d6, r7, s13); 125980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 126080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(lr); 126180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load lhs to a double in r2, r3. 126280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ldrd(r2, r3, FieldMemOperand(lhs, HeapNumber::kValueOffset)); 126380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Convert rhs to a double in r0, r1. 126480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r7, Operand(rhs)); 126580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ConvertToDoubleStub stub2(r1, r0, r7, r6); 12663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Call(stub2.GetCode()); 126780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(lr); 126880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 126980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fall through to both_loaded_as_doubles. 127080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 127180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 127280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 12731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cond) { 127480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset); 127580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register rhs_exponent = exp_first ? r0 : r1; 127680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register lhs_exponent = exp_first ? r2 : r3; 127780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register rhs_mantissa = exp_first ? r1 : r0; 127880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register lhs_mantissa = exp_first ? r3 : r2; 127980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label one_is_nan, neither_is_nan; 128080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 128180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Sbfx(r4, 128280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen lhs_exponent, 128380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen HeapNumber::kExponentShift, 128480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen HeapNumber::kExponentBits); 128580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NaNs have all-one exponents so they sign extend to -1. 128680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r4, Operand(-1)); 128780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, lhs_not_nan); 128880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r4, 128980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Operand(lhs_exponent, LSL, HeapNumber::kNonMantissaBitsInTopWord), 129080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SetCC); 129180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &one_is_nan); 12929ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ cmp(lhs_mantissa, Operand(0, RelocInfo::NONE)); 129380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &one_is_nan); 129480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 129580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(lhs_not_nan); 129680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Sbfx(r4, 129780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen rhs_exponent, 129880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen HeapNumber::kExponentShift, 129980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen HeapNumber::kExponentBits); 130080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NaNs have all-one exponents so they sign extend to -1. 130180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r4, Operand(-1)); 130280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &neither_is_nan); 130380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r4, 130480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Operand(rhs_exponent, LSL, HeapNumber::kNonMantissaBitsInTopWord), 130580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen SetCC); 130680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &one_is_nan); 13079ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ cmp(rhs_mantissa, Operand(0, RelocInfo::NONE)); 130880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &neither_is_nan); 130980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 131080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&one_is_nan); 131180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NaN comparisons always fail. 131280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load whatever we need in r0 to make the comparison fail. 13131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (cond == lt || cond == le) { 131480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(GREATER)); 131580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 131680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(LESS)); 131780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 131880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 131980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 132080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&neither_is_nan); 132180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 132280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 132380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 132480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// See comment at call site. 13251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockstatic void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, 13261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Condition cond) { 132780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset); 132880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register rhs_exponent = exp_first ? r0 : r1; 132980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register lhs_exponent = exp_first ? r2 : r3; 133080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register rhs_mantissa = exp_first ? r1 : r0; 133180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register lhs_mantissa = exp_first ? r3 : r2; 133280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 133380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0, r1, r2, r3 have the two doubles. Neither is a NaN. 13341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (cond == eq) { 133580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Doubles are not equal unless they have the same bit pattern. 133680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Exception: 0 and -0. 133780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(rhs_mantissa, Operand(lhs_mantissa)); 133880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ orr(r0, rhs_mantissa, Operand(lhs_mantissa), LeaveCC, ne); 133980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return non-zero if the numbers are unequal. 134080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(ne); 134180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 134280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(r0, rhs_exponent, Operand(lhs_exponent), SetCC); 134380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If exponents are equal then return 0. 134480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(eq); 134580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 134680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Exponents are unequal. The only way we can return that the numbers 134780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // are equal is if one is -0 and the other is 0. We already dealt 134880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // with the case where both are -0 or both are 0. 134980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // We start by seeing if the mantissas (that are equal) or the bottom 135080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // 31 bits of the rhs exponent are non-zero. If so we return not 135180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // equal. 135280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ orr(r4, lhs_mantissa, Operand(lhs_exponent, LSL, kSmiTagSize), SetCC); 135380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(r4), LeaveCC, ne); 135480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(ne); 135580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Now they are equal if and only if the lhs exponent is zero in its 135680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // low 31 bits. 135780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(rhs_exponent, LSL, kSmiTagSize)); 135880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 135980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 136080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call a native function to do a comparison between two non-NaNs. 136180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call C routine that may not cause GC or other trouble. 136280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(lr); 1363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ PrepareCallCFunction(0, 2, r5); 1364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (masm->use_eabi_hardfloat()) { 1365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CpuFeatures::Scope scope(VFP3); 1366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ vmov(d0, r0, r1); 1367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ vmov(d1, r2, r3); 1368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 13693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 13703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch AllowExternalCallThatCantCauseGC scope(masm); 1371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallCFunction(ExternalReference::compare_doubles(masm->isolate()), 1372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 0, 2); 137380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(pc); // Return. 137480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 137580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 137680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 137780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 137880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// See comment at call site. 137980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, 138080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register lhs, 138180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register rhs) { 138280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT((lhs.is(r0) && rhs.is(r1)) || 138380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen (lhs.is(r1) && rhs.is(r0))); 138480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 13853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // If either operand is a JS object or an oddball value, then they are 138680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // not equal since their pointers are different. 138780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // There is no test for undetectability in strict equality. 13883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); 138980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label first_non_object; 139080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the type of the first operand into r2 and compare it with 13913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // FIRST_SPEC_OBJECT_TYPE. 13923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CompareObjectType(rhs, r2, r2, FIRST_SPEC_OBJECT_TYPE); 139380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(lt, &first_non_object); 139480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 139580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return non-zero (r0 is not zero) 139680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label return_not_equal; 139780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&return_not_equal); 139880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 139980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 140080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&first_non_object); 140180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for oddballs: true, false, null, undefined. 140280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r2, Operand(ODDBALL_TYPE)); 140380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &return_not_equal); 140480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 14053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CompareObjectType(lhs, r3, r3, FIRST_SPEC_OBJECT_TYPE); 140680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ge, &return_not_equal); 140780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 140880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for oddballs: true, false, null, undefined. 140980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r3, Operand(ODDBALL_TYPE)); 141080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &return_not_equal); 141180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 141280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Now that we have the types we might as well check for symbol-symbol. 141380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Ensure that no non-strings have the symbol bit set. 141480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask); 141580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSymbolTag != 0); 141680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(r2, r2, Operand(r3)); 141780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(r2, Operand(kIsSymbolMask)); 141880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &return_not_equal); 141980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 142080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 142180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 142280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// See comment at call site. 142380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, 142480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register lhs, 142580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register rhs, 142680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* both_loaded_as_doubles, 142780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_heap_numbers, 142880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* slow) { 142980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT((lhs.is(r0) && rhs.is(r1)) || 143080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen (lhs.is(r1) && rhs.is(r0))); 143180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 143280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareObjectType(rhs, r3, r2, HEAP_NUMBER_TYPE); 143380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, not_heap_numbers); 143480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r2, FieldMemOperand(lhs, HeapObject::kMapOffset)); 143580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r2, r3); 143680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, slow); // First was a heap number, second wasn't. Go slow case. 143780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 143880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both are heap numbers. Load them up then jump to the code we have 143980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // for that. 14408b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 144180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope scope(VFP3); 144280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(r7, rhs, Operand(kHeapObjectTag)); 144380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ vldr(d6, r7, HeapNumber::kValueOffset); 144480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(r7, lhs, Operand(kHeapObjectTag)); 144580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ vldr(d7, r7, HeapNumber::kValueOffset); 144680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 144780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ldrd(r2, r3, FieldMemOperand(lhs, HeapNumber::kValueOffset)); 144880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset)); 144980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 145080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(both_loaded_as_doubles); 145180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 145280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 145380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 145480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Fast negative check for symbol-to-symbol equality. 145580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic void EmitCheckForSymbolsOrObjects(MacroAssembler* masm, 145680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register lhs, 145780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register rhs, 145880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* possible_strings, 145980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_both_strings) { 146080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT((lhs.is(r0) && rhs.is(r1)) || 146180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen (lhs.is(r1) && rhs.is(r0))); 146280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 146380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2 is object type of rhs. 146480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Ensure that no non-strings have the symbol bit set. 146580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label object_test; 146680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSymbolTag != 0); 146780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(r2, Operand(kIsNotStringMask)); 146880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &object_test); 146980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(r2, Operand(kIsSymbolMask)); 147080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, possible_strings); 147180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareObjectType(lhs, r3, r3, FIRST_NONSTRING_TYPE); 147280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ge, not_both_strings); 147380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(r3, Operand(kIsSymbolMask)); 147480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, possible_strings); 147580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 147680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both are symbols. We already checked they weren't the same pointer 147780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // so they are not equal. 147880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(NOT_EQUAL)); 147980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 148080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 148180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&object_test); 14823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(r2, Operand(FIRST_SPEC_OBJECT_TYPE)); 148380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(lt, not_both_strings); 14843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CompareObjectType(lhs, r2, r3, FIRST_SPEC_OBJECT_TYPE); 148580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(lt, not_both_strings); 148680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If both objects are undetectable, they are equal. Otherwise, they 148780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // are not equal, since they are different objects and an object is not 148880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // equal to undefined. 148980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, FieldMemOperand(rhs, HeapObject::kMapOffset)); 149080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(r2, FieldMemOperand(r2, Map::kBitFieldOffset)); 149180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset)); 149280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(r0, r2, Operand(r3)); 149380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(r0, r0, Operand(1 << Map::kIsUndetectable)); 149480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ eor(r0, r0, Operand(1 << Map::kIsUndetectable)); 149580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 149680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 149780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 149880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 149980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, 150080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register object, 150180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register result, 150280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 150380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 150480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch3, 150580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool object_is_smi, 150680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_found) { 150780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Use of registers. Register result is used as a temporary. 150880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register number_string_cache = result; 150980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register mask = scratch3; 151080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 151180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the number string cache. 151280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex); 151380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 151480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make the hash mask from the length of the number string cache. It 151580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // contains two elements (number and string) for each cache entry. 151680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset)); 151780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Divide length by two (length is a smi). 151880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(mask, Operand(mask, ASR, kSmiTagSize + 1)); 151980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(mask, mask, Operand(1)); // Make mask. 152080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 152180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate the entry in the number string cache. The hash value in the 152280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // number string cache for smis is just the smi value, and the hash for 152380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // doubles is the xor of the upper and lower words. See 152480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Heap::GetNumberStringCache. 152544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate* isolate = masm->isolate(); 152680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label is_smi; 152780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label load_result_from_cache; 152880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!object_is_smi) { 15291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfSmi(object, &is_smi); 15308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 153180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope scope(VFP3); 153280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CheckMap(object, 153380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch1, 153480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Heap::kHeapNumberMapRootIndex, 153580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen not_found, 1536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch DONT_DO_SMI_CHECK); 153780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 153880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(8 == kDoubleSize); 153980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(scratch1, 154080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen object, 154180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Operand(HeapNumber::kValueOffset - kHeapObjectTag)); 154280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit()); 154380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ eor(scratch1, scratch1, Operand(scratch2)); 154480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(scratch1, scratch1, Operand(mask)); 154580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 154680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate address of entry in string cache: each entry consists 154780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // of two pointer sized fields. 154880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(scratch1, 154980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen number_string_cache, 155080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Operand(scratch1, LSL, kPointerSizeLog2 + 1)); 155180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 155280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register probe = mask; 155380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(probe, 155480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldMemOperand(scratch1, FixedArray::kHeaderSize)); 15551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfSmi(probe, not_found); 155680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(scratch2, object, Operand(kHeapObjectTag)); 155780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ vldr(d0, scratch2, HeapNumber::kValueOffset); 155880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(probe, probe, Operand(kHeapObjectTag)); 155980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ vldr(d1, probe, HeapNumber::kValueOffset); 1560b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ VFPCompareAndSetFlags(d0, d1); 156180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, not_found); // The cache did not contain this value. 156280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(&load_result_from_cache); 156380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 156480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(not_found); 156580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 156680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 156780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 156880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&is_smi); 156980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch = scratch1; 157080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(scratch, mask, Operand(object, ASR, 1)); 157180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate address of entry in string cache: each entry consists 157280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // of two pointer sized fields. 157380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(scratch, 157480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen number_string_cache, 157580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Operand(scratch, LSL, kPointerSizeLog2 + 1)); 157680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 157780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the entry is the smi we are looking for. 157880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register probe = mask; 157980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize)); 158080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(object, probe); 158180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, not_found); 158280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 158380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the result from the cache. 158480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&load_result_from_cache); 158580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(result, 158680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize)); 158744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(isolate->counters()->number_to_string_native(), 158880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 1, 158980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch1, 159080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch2); 159180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 159280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 159380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 159480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::Generate(MacroAssembler* masm) { 159580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 159680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 159780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r1, MemOperand(sp, 0)); 159880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 159980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Generate code to lookup number in the number string cache. 160080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateLookupNumberStringCache(masm, r1, r0, r2, r3, r4, false, &runtime); 160180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(sp, sp, Operand(1 * kPointerSize)); 160280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 160380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 160480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 160580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle number to string in the runtime system if not found in the cache. 160680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1); 160780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 160880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 160980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 161080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// On entry lhs_ and rhs_ are the values to be compared. 161180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// On exit r0 is 0, positive or negative to indicate the result of 161280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// the comparison. 161380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::Generate(MacroAssembler* masm) { 161480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT((lhs_.is(r0) && rhs_.is(r1)) || 161580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen (lhs_.is(r1) && rhs_.is(r0))); 161680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 161780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow; // Call builtin. 161880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label not_smis, both_loaded_as_doubles, lhs_not_nan; 161980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 16200d5e116f6aee03185f237311a943491bb079a768Kristian Monsen if (include_smi_compare_) { 16210d5e116f6aee03185f237311a943491bb079a768Kristian Monsen Label not_two_smis, smi_done; 16220d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ orr(r2, r1, r0); 16233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(r2, ¬_two_smis); 1624f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch __ mov(r1, Operand(r1, ASR, 1)); 1625f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch __ sub(r0, r1, Operand(r0, ASR, 1)); 16260d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ Ret(); 16270d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ bind(¬_two_smis); 16280d5e116f6aee03185f237311a943491bb079a768Kristian Monsen } else if (FLAG_debug_code) { 16290d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ orr(r2, r1, r0); 16300d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ tst(r2, Operand(kSmiTagMask)); 16311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Assert(ne, "CompareStub: unexpected smi operands."); 16320d5e116f6aee03185f237311a943491bb079a768Kristian Monsen } 16330d5e116f6aee03185f237311a943491bb079a768Kristian Monsen 163480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NOTICE! This code is only reached after a smi-fast-case check, so 163580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // it is certain that at least one operand isn't a smi. 163680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 163780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle the case where the objects are identical. Either returns the answer 163880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // or goes to slow. Only falls through if the objects were not identical. 163980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); 164080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 164180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If either is a Smi (we know that not both are), then they can only 164280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // be strictly equal if the other is a HeapNumber. 164380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 164480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT_EQ(0, Smi::FromInt(0)); 164580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(r2, lhs_, Operand(rhs_)); 16463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(r2, ¬_smis); 164780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // One operand is a smi. EmitSmiNonsmiComparison generates code that can: 164880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // 1) Return the answer. 164980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // 2) Go to slow. 165080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // 3) Fall through to both_loaded_as_doubles. 165180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // 4) Jump to lhs_not_nan. 165280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // In cases 3 and 4 we have found out we were dealing with a number-number 165380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // comparison. If VFP3 is supported the double values of the numbers have 165480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // been loaded into d7 and d6. Otherwise, the double values have been loaded 165580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // into r0, r1, r2, and r3. 165680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen EmitSmiNonsmiComparison(masm, lhs_, rhs_, &lhs_not_nan, &slow, strict_); 165780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 165880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&both_loaded_as_doubles); 165980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The arguments have been converted to doubles and stored in d6 and d7, if 166080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // VFP3 is supported, or in r0, r1, r2, and r3. 166144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate* isolate = masm->isolate(); 16628b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 166380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&lhs_not_nan); 166480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope scope(VFP3); 166580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label no_nan; 166680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ARMv7 VFP3 instructions to implement double precision comparison. 1667b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ VFPCompareAndSetFlags(d7, d6); 166880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label nan; 166980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(vs, &nan); 167080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(EQUAL), LeaveCC, eq); 167180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(LESS), LeaveCC, lt); 167280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(GREATER), LeaveCC, gt); 167380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 167480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 167580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&nan); 167680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If one of the sides was a NaN then the v flag is set. Load r0 with 167780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // whatever it takes to make the comparison fail, since comparisons with NaN 167880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // always fail. 167980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == lt || cc_ == le) { 168080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(GREATER)); 168180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 168280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(LESS)); 168380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 168480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 168580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 168680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Checks for NaN in the doubles we have loaded. Can return the answer or 168780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // fall through if neither is a NaN. Also binds lhs_not_nan. 168880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen EmitNanCheck(masm, &lhs_not_nan, cc_); 168980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compares two doubles in r0, r1, r2, r3 that are not NaNs. Returns the 169080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // answer. Never falls through. 169180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen EmitTwoNonNanDoubleComparison(masm, cc_); 169280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 169380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 169480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_smis); 169580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // At this point we know we are dealing with two different objects, 169680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and neither of them is a Smi. The objects are in rhs_ and lhs_. 169780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (strict_) { 169880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // This returns non-equal for some object types, or falls through if it 169980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // was not lucky. 170080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen EmitStrictTwoHeapObjectCompare(masm, lhs_, rhs_); 170180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 170280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 170380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label check_for_symbols; 170480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label flat_string_check; 170580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for heap-number-heap-number comparison. Can jump to slow case, 170680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // or load both doubles into r0, r1, r2, r3 and jump to the code that handles 170780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // that case. If the inputs are not doubles then jumps to check_for_symbols. 170880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // In this case r2 will contain the type of rhs_. Never falls through. 170980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen EmitCheckForTwoHeapNumbers(masm, 171080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen lhs_, 171180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen rhs_, 171280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &both_loaded_as_doubles, 171380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &check_for_symbols, 171480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &flat_string_check); 171580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 171680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&check_for_symbols); 171780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // In the strict case the EmitStrictTwoHeapObjectCompare already took care of 171880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // symbols. 171980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == eq && !strict_) { 172080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Returns an answer for two symbols or two detectable objects. 172180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Otherwise jumps to string case or not both strings case. 172280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Assumes that r2 is the type of rhs_ on entry. 172380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen EmitCheckForSymbolsOrObjects(masm, lhs_, rhs_, &flat_string_check, &slow); 172480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 172580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 172680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for both being sequential ASCII strings, and inline if that is the 172780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // case. 172880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&flat_string_check); 172980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 173080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs_, rhs_, r2, r3, &slow); 173180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 173244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(isolate->counters()->string_compare_native(), 1, r2, r3); 1733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (cc_ == eq) { 1734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringCompareStub::GenerateFlatAsciiStringEquals(masm, 173580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen lhs_, 173680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen rhs_, 173780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen r2, 173880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen r3, 1739257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r4); 1740257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 1741257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringCompareStub::GenerateCompareFlatAsciiStrings(masm, 1742257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch lhs_, 1743257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch rhs_, 1744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r2, 1745257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r3, 1746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r4, 1747257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r5); 1748257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 174980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Never falls through to here. 175080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 175180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 175280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 175380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Push(lhs_, rhs_); 175480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Figure out which native to call and setup the arguments. 175580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Builtins::JavaScript native; 175680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == eq) { 175780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen native = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; 175880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 175980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen native = Builtins::COMPARE; 176080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int ncr; // NaN compare result 176180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (cc_ == lt || cc_ == le) { 176280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ncr = GREATER; 176380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 176480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(cc_ == gt || cc_ == ge); // remaining cases 176580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ncr = LESS; 176680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 176780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(Smi::FromInt(ncr))); 176880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(r0); 176980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 177080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 177180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) 177280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // tagged as a small integer. 1773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(native, JUMP_FUNCTION); 177480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 177580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 177680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 177769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch// The stub expects its argument in the tos_ register and returns its result in 177869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch// it, too: zero for false, and a non-zero value for true. 177980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ToBooleanStub::Generate(MacroAssembler* masm) { 17803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // This stub overrides SometimesSetsUpAFrame() to return false. That means 17813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // we cannot call anything that could cause a GC from this stub. 1782e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // This stub uses VFP3 instructions. 1783257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CpuFeatures::Scope scope(VFP3); 1784e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 178569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label patch; 17863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const Register map = r9.is(tos_) ? r7 : r9; 178780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 178869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // undefined -> false. 178969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false); 1790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 179169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Boolean -> its value. 179269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false); 179369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true); 1794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 179569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // 'null' -> false. 179669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false); 1797b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 179869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(SMI)) { 179969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Smis: 0 -> false, all other -> true 180069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ tst(tos_, Operand(kSmiTagMask)); 180169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // tos_ contains the correct return value already 180269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Ret(eq); 180369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } else if (types_.NeedsMap()) { 180469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If we need a map later and have a Smi -> patch. 180569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ JumpIfSmi(tos_, &patch); 180669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 18073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 180869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.NeedsMap()) { 180969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ldr(map, FieldMemOperand(tos_, HeapObject::kMapOffset)); 18103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 181169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.CanBeUndetectable()) { 181269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset)); 181369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ tst(ip, Operand(1 << Map::kIsUndetectable)); 181469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Undetectable -> false. 181569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne); 181669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Ret(ne); 181769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 181869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 181969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 182069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(SPEC_OBJECT)) { 182169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Spec object -> true. 182269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE); 182369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // tos_ contains the correct non-zero return value already. 182469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Ret(ge); 182569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 18263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 182769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(STRING)) { 182869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // String value -> false iff empty. 18293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE); 183069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt); 183169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Ret(lt); // the string length is OK as the return value 183269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 18333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 183469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(HEAP_NUMBER)) { 183569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Heap number -> false iff +0, -0, or NaN. 183669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label not_heap_number; 183769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); 183869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ b(ne, ¬_heap_number); 183969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ vldr(d1, FieldMemOperand(tos_, HeapNumber::kValueOffset)); 184069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ VFPCompareAndSetFlags(d1, 0.0); 184169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // "tos_" is a register, and contains a non zero value by default. 184269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Hence we only need to overwrite "tos_" with zero to return false for 184369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true. 184469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq); // for FP_ZERO 184569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, vs); // for FP_NAN 184669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Ret(); 184769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(¬_heap_number); 184869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 184980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 185069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&patch); 185169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch GenerateTypeTransition(masm); 185269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch} 185369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 185469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 185569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid ToBooleanStub::CheckOddball(MacroAssembler* masm, 185669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Type type, 185769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Heap::RootListIndex value, 185869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch bool result) { 185969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (types_.Contains(type)) { 186069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If we see an expected oddball, return its ToBoolean value tos_. 186169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ LoadRoot(ip, value); 186269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(tos_, ip); 186369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // The value of a root is never NULL, so we can avoid loading a non-null 186469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // value into tos_ when we want to return 'true'. 186569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!result) { 186669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq); 186769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 186869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Ret(eq); 186969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 187069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch} 187169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 187269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 187369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) { 187469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (!tos_.is(r3)) { 187569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(r3, Operand(tos_)); 187669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 187769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(r2, Operand(Smi::FromInt(tos_.code()))); 187869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(r1, Operand(Smi::FromInt(types_.ToByte()))); 187969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ Push(r3, r2, r1); 188069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Patch the caller to an appropriate specialized stub and return the 188169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // operation result to the caller of the stub. 188269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ TailCallExternalReference( 188369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()), 188469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 3, 188569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 1); 188680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 188780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 188880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 18893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StoreBufferOverflowStub::Generate(MacroAssembler* masm) { 18903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // We don't allow a GC during a store buffer overflow so there is no need to 18913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // store the registers in any particular way, but we do have to store and 18923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // restore them. 18933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ stm(db_w, sp, kCallerSaved | lr.bit()); 18943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (save_doubles_ == kSaveFPRegs) { 18953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CpuFeatures::Scope scope(VFP3); 18963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(sp, sp, Operand(kDoubleSize * DwVfpRegister::kNumRegisters)); 18973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) { 18983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch DwVfpRegister reg = DwVfpRegister::from_code(i); 18993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vstr(reg, MemOperand(sp, i * kDoubleSize)); 19003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 19013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 19023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int argument_count = 1; 19033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int fp_argument_count = 0; 19043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const Register scratch = r1; 19053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 19063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch AllowExternalCallThatCantCauseGC scope(masm); 19073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ PrepareCallCFunction(argument_count, fp_argument_count, scratch); 19083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r0, Operand(ExternalReference::isolate_address())); 19093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallCFunction( 19103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference::store_buffer_overflow_function(masm->isolate()), 19113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch argument_count); 19123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (save_doubles_ == kSaveFPRegs) { 19133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CpuFeatures::Scope scope(VFP3); 19143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) { 19153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch DwVfpRegister reg = DwVfpRegister::from_code(i); 19163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vldr(reg, MemOperand(sp, i * kDoubleSize)); 19173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 19183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(sp, sp, Operand(kDoubleSize * DwVfpRegister::kNumRegisters)); 19193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 19203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldm(ia_w, sp, kCallerSaved | pc.bit()); // Also pop pc to get Ret(0). 19213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 19223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 19233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 19243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid UnaryOpStub::PrintName(StringStream* stream) { 1925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const char* op_name = Token::Name(op_); 1926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const char* overwrite_name = NULL; // Make g++ happy. 1927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (mode_) { 1928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; 1929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; 1930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 19313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("UnaryOpStub_%s_%s_%s", 19323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch op_name, 19333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch overwrite_name, 19343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch UnaryOpIC::GetName(operand_type_)); 1935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1937257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1938257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 1939257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::Generate(MacroAssembler* masm) { 1940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (operand_type_) { 1941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::UNINITIALIZED: 1942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 1943257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 1944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::SMI: 1945257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStub(masm); 1946257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 1947257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::HEAP_NUMBER: 1948257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStub(masm); 1949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 1950257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case UnaryOpIC::GENERIC: 1951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStub(masm); 1952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 1953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 1954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 19583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(r3, Operand(r0)); // the operand 19593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(r2, Operand(Smi::FromInt(op_))); 19603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(r1, Operand(Smi::FromInt(mode_))); 1961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, Operand(Smi::FromInt(operand_type_))); 1962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Push(r3, r2, r1, r0); 1963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1964257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ TailCallExternalReference( 19653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1); 1966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1969257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 1970257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 1971257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 1972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 1973257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStubSub(masm); 1974257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 1975257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 1976257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiStubBitNot(masm); 1977257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 1978257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 1979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 1980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 1981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1982257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1984257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) { 1985257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow; 1986257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &non_smi, &slow); 1987257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 1988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 1989257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 1990257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1991257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) { 1994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi; 1995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi); 1996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 1997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 1998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 1999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, 2002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* non_smi, 2003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* slow) { 2004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfNotSmi(r0, non_smi); 2005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // The result of negating zero or the smallest negative smi is not a smi. 2007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bic(ip, r0, Operand(0x80000000), SetCC); 2008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(eq, slow); 2009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Return '0 - value'. 2011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ rsb(r0, r0, Operand(0, RelocInfo::NONE)); 2012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Ret(); 2013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 2014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeBitNot(MacroAssembler* masm, 2017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* non_smi) { 2018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfNotSmi(r0, non_smi); 2019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Flip bits and revert inverted smi-tag. 2021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mvn(r0, Operand(r0)); 2022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bic(r0, r0, Operand(kSmiTagMask)); 2023257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Ret(); 2024257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 2025257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2026257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2027257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 2028257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 2029257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 2030257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 2031257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStubSub(masm); 2032257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 2033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 2034257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberStubBitNot(masm); 2035257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 2036257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 2037257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 2038257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 2039257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 2040257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2041257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2042257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) { 2043257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow, call_builtin; 2044257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &non_smi, &call_builtin); 2045257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 2046257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeSub(masm, &slow); 2047257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 2048257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 2049257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_builtin); 2050257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 2051257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 2052257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2053257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2054257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubBitNot(MacroAssembler* masm) { 2055257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow; 2056257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi); 2057257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 2058257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeBitNot(masm, &slow); 2059257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 2060257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 2061257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 2062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2063257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, 2064257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* slow) { 2065257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch EmitCheckForHeapNumber(masm, r0, r1, r6, slow); 2066257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // r0 is a heap number. Get a new heap number in r1. 2067257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (mode_ == UNARY_OVERWRITE) { 2068257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); 2069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. 2070257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); 2071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 2072257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label slow_allocate_heapnumber, heapnumber_allocated; 2073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ AllocateHeapNumber(r1, r2, r3, r6, &slow_allocate_heapnumber); 2074257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&heapnumber_allocated); 2075257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2076257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow_allocate_heapnumber); 20773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 20783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FrameScope scope(masm, StackFrame::INTERNAL); 20793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(r0); 20803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallRuntime(Runtime::kNumberAlloc, 0); 20813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r1, Operand(r0)); 20823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(r0); 20833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2084257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2085257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&heapnumber_allocated); 2086257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); 2087257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); 2088257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ str(r3, FieldMemOperand(r1, HeapNumber::kMantissaOffset)); 2089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. 2090257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ str(r2, FieldMemOperand(r1, HeapNumber::kExponentOffset)); 2091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, Operand(r1)); 2092257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 2093257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Ret(); 2094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 2095257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2097257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeBitNot( 2098257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, Label* slow) { 20993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label impossible; 21003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 2101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch EmitCheckForHeapNumber(masm, r0, r1, r6, slow); 2102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Convert the heap number is r0 to an untagged integer in r1. 2103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ConvertToInt32(r0, r1, r2, r3, d0, slow); 2104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Do the bitwise operation and check if the result fits in a smi. 2106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label try_float; 2107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mvn(r1, Operand(r1)); 2108257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(r2, r1, Operand(0x40000000), SetCC); 2109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(mi, &try_float); 2110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Tag the result as a smi and we're done. 2112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, Operand(r1, LSL, kSmiTagSize)); 2113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Ret(); 2114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Try to store the result in a heap number. 2116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&try_float); 2117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (mode_ == UNARY_NO_OVERWRITE) { 2118257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label slow_allocate_heapnumber, heapnumber_allocated; 21193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Allocate a new heap number without zapping r0, which we need if it fails. 21203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ AllocateHeapNumber(r2, r3, r4, r6, &slow_allocate_heapnumber); 2121257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ jmp(&heapnumber_allocated); 2122257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2123257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow_allocate_heapnumber); 21243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 21253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FrameScope scope(masm, StackFrame::INTERNAL); 21263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(r0); // Push the heap number, not the untagged int32. 21273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallRuntime(Runtime::kNumberAlloc, 0); 21283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r2, r0); // Move the new heap number into r2. 21293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Get the heap number into r0, now that the new heap number is in r2. 21303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(r0); 21313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2132257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 21333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Convert the heap number in r0 to an untagged integer in r1. 21343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // This can't go slow-case because it's the same number we already 21353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // converted once again. 21363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ConvertToInt32(r0, r1, r3, r4, d0, &impossible); 21373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mvn(r1, Operand(r1)); 21383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 2139257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&heapnumber_allocated); 21403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(r0, r2); // Move newly allocated heap number to r0. 2141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 2142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 2144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Convert the int32 in r1 to the heap number in r0. r2 is corrupted. 2145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CpuFeatures::Scope scope(VFP3); 2146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ vmov(s0, r1); 2147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ vcvt_f64_s32(d0, s0); 2148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sub(r2, r0, Operand(kHeapObjectTag)); 2149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ vstr(d0, r2, HeapNumber::kValueOffset); 2150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Ret(); 2151257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 2152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // WriteInt32ToHeapNumberStub does not trigger GC, so we do not 2153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // have to set up a frame. 2154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch WriteInt32ToHeapNumberStub stub(r1, r0, r2); 2155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); 2156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 21573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 21583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&impossible); 21593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (FLAG_debug_code) { 21603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ stop("Incorrect assumption in bit-not stub"); 21613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch } 2162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 2163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2165257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch. 2166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) { 2167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 2168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 2169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStubSub(masm); 2170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 2171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 2172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericStubBitNot(masm); 2173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 2174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 2175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 2176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 2177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 2178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) { 2181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow; 2182257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeSub(masm, &non_smi, &slow); 2183257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 2184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeSub(masm, &slow); 2185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 2186257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 2187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 2188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) { 2191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label non_smi, slow; 2192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateSmiCodeBitNot(masm, &non_smi); 2193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&non_smi); 2194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateHeapNumberCodeBitNot(masm, &slow); 2195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&slow); 2196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateGenericCodeFallback(masm); 2197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 2198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) { 2201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle the slow case by jumping to the JavaScript builtin. 2202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ push(r0); 2203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch switch (op_) { 2204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::SUB: 2205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION); 2206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 2207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case Token::BIT_NOT: 2208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); 2209257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 2210257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch default: 2211257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch UNREACHABLE(); 2212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 2213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 2214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 22171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label get_result; 22181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 22191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Push(r1, r0); 22201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 22211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(r2, Operand(Smi::FromInt(MinorKey()))); 22221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(r1, Operand(Smi::FromInt(op_))); 22231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(r0, Operand(Smi::FromInt(operands_type_))); 22241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Push(r2, r1, r0); 22251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 22261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ TailCallExternalReference( 2227257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ExternalReference(IC_Utility(IC::kBinaryOp_Patch), 222844f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()), 22291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 5, 22301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 1); 22311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 22321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 22331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2234257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransitionWithSavedArgs( 22351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block MacroAssembler* masm) { 2236b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch UNIMPLEMENTED(); 22371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 22381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 22391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::Generate(MacroAssembler* masm) { 22413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Explicitly allow generation of nested stubs. It is safe here because 22423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // generation code does not use any raw pointers. 22433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch AllowStubCallsScope allow_stub_calls(masm, true); 22443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 22451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block switch (operands_type_) { 2246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::UNINITIALIZED: 22471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateTypeTransition(masm); 22481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 2249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::SMI: 22501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateSmiStub(masm); 22511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 2252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::INT32: 22531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateInt32Stub(masm); 22541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 2255257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::HEAP_NUMBER: 22561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateHeapNumberStub(masm); 22571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 2258257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::ODDBALL: 225944f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateOddballStub(masm); 226044f0eee88ff00398ff7f715fab053374d808c90dSteve Block break; 2261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::BOTH_STRING: 2262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateBothStringStub(masm); 2263257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch break; 2264257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::STRING: 22651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateStringStub(masm); 22661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 2267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch case BinaryOpIC::GENERIC: 22681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateGeneric(masm); 22691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 22701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block default: 22711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block UNREACHABLE(); 22721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 22731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 22741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 22751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 22763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid BinaryOpStub::PrintName(StringStream* stream) { 22771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block const char* op_name = Token::Name(op_); 22781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block const char* overwrite_name; 22791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block switch (mode_) { 22801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case NO_OVERWRITE: overwrite_name = "Alloc"; break; 22811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; 22821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; 22831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block default: overwrite_name = "UnknownOverwrite"; break; 22841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 22853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("BinaryOpStub_%s_%s_%s", 22863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch op_name, 22873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch overwrite_name, 22883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch BinaryOpIC::GetName(operands_type_)); 22891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 22901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 22911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2292257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiSmiOperation(MacroAssembler* masm) { 22931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register left = r1; 22941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register right = r0; 22951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch1 = r7; 22961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch2 = r9; 22971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 22981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(right.is(r0)); 22991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block STATIC_ASSERT(kSmiTag == 0); 23001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 23011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label not_smi_result; 23021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block switch (op_) { 23031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::ADD: 23041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ add(right, left, Operand(right), SetCC); // Add optimistically. 23051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(vc); 23061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ sub(right, right, Operand(left)); // Revert optimistic add. 23071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 23081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SUB: 23091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ sub(right, left, Operand(right), SetCC); // Subtract optimistically. 23101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(vc); 23111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ sub(right, left, Operand(right)); // Revert optimistic subtract. 23121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 23131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::MUL: 23141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Remove tag from one of the operands. This way the multiplication result 23151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // will be a smi if it fits the smi range. 23161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiUntag(ip, right); 23171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Do multiplication 23181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // scratch1 = lower 32 bits of ip * left. 23191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // scratch2 = higher 32 bits of ip * left. 23201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ smull(scratch1, scratch2, left, ip); 23211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check for overflowing the smi range - no overflow if higher 33 bits of 23221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // the result are identical. 23231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(ip, Operand(scratch1, ASR, 31)); 23241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ cmp(ip, Operand(scratch2)); 23251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ b(ne, ¬_smi_result); 23261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Go slow on zero result to handle -0. 23273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(scratch1, Operand(0)); 23281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(right, Operand(scratch1), LeaveCC, ne); 23291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(ne); 23301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // We need -0 if we were multiplying a negative number with 0 to get 0. 23311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // We know one of them was zero. 23321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ add(scratch2, right, Operand(left), SetCC); 23331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl); 23341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(pl); // Return smi 0 if the non-zero one was positive. 23351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // We fall through here if we multiplied a negative number with 0, because 23361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // that would mean we should produce -0. 23371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 23381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::DIV: 23391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check for power of two on the right hand side. 23401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfNotPowerOfTwoOrZero(right, scratch1, ¬_smi_result); 23411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check for positive and no remainder (scratch1 contains right - 1). 23421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ orr(scratch2, scratch1, Operand(0x80000000u)); 23431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ tst(left, scratch2); 23441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ b(ne, ¬_smi_result); 23451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 23461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Perform division by shifting. 23471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CountLeadingZeros(scratch1, scratch1, scratch2); 23481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ rsb(scratch1, scratch1, Operand(31)); 23491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(right, Operand(left, LSR, scratch1)); 23501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 23511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 23521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::MOD: 23531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check for two positive smis. 23541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ orr(scratch1, left, Operand(right)); 23551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ tst(scratch1, Operand(0x80000000u | kSmiTagMask)); 23561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ b(ne, ¬_smi_result); 23571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 23581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check for power of two on the right hand side. 23591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfNotPowerOfTwoOrZero(right, scratch1, ¬_smi_result); 23601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 23611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Perform modulus by masking. 23621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ and_(right, left, Operand(scratch1)); 23631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 23641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 23651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_OR: 23661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ orr(right, left, Operand(right)); 23671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 23681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 23691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_AND: 23701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ and_(right, left, Operand(right)); 23711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 23721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 23731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_XOR: 23741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ eor(right, left, Operand(right)); 23751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 23761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 23771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SAR: 23781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Remove tags from right operand. 23791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ GetLeastBitsFromSmi(scratch1, right, 5); 23801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(right, Operand(left, ASR, scratch1)); 23811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Smi tag result. 23821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bic(right, right, Operand(kSmiTagMask)); 23831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 23841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 23851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SHR: 23861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Remove tags from operands. We can't do this on a 31 bit number 23871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // because then the 0s get shifted into bit 30 instead of bit 31. 23881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiUntag(scratch1, left); 23891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ GetLeastBitsFromSmi(scratch2, right, 5); 23901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(scratch1, Operand(scratch1, LSR, scratch2)); 23911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Unsigned shift is not allowed to produce a negative number, so 23921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // check the sign bit and the sign bit after Smi tagging. 23931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ tst(scratch1, Operand(0xc0000000)); 23941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ b(ne, ¬_smi_result); 23951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Smi tag result. 23961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiTag(right, scratch1); 23971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 23981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 23991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SHL: 24001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Remove tags from operands. 24011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiUntag(scratch1, left); 24021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ GetLeastBitsFromSmi(scratch2, right, 5); 24031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(scratch1, Operand(scratch1, LSL, scratch2)); 24041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check that the signed result fits in a Smi. 24051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ add(scratch2, scratch1, Operand(0x40000000), SetCC); 24061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ b(mi, ¬_smi_result); 24071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiTag(right, scratch1); 24081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 24091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 24101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block default: 24111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block UNREACHABLE(); 24121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 24131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(¬_smi_result); 24141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 24151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 24161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, 2418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch bool smi_operands, 2419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* not_numbers, 2420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* gc_required) { 24211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register left = r1; 24221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register right = r0; 24231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch1 = r7; 24241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch2 = r9; 242544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Register scratch3 = r4; 24261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 24271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(smi_operands || (not_numbers != NULL)); 24281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (smi_operands && FLAG_debug_code) { 24291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ AbortIfNotSmi(left); 24301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ AbortIfNotSmi(right); 24311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 24321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 24331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register heap_number_map = r6; 24341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 24351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 24361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block switch (op_) { 24371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::ADD: 24381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SUB: 24391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::MUL: 24401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::DIV: 24411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::MOD: { 24421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Load left and right operands into d6 and d7 or r0/r1 and r2/r3 24431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // depending on whether VFP3 is available or not. 24441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block FloatingPointHelper::Destination destination = 24458b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch CpuFeatures::IsSupported(VFP3) && 244644f0eee88ff00398ff7f715fab053374d808c90dSteve Block op_ != Token::MOD ? 24471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block FloatingPointHelper::kVFPRegisters : 24481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block FloatingPointHelper::kCoreRegisters; 24491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 24501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Allocate new heap number for result. 24511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register result = r5; 2452e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateHeapResultAllocation( 2453e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch masm, result, heap_number_map, scratch1, scratch2, gc_required); 24541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 24551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Load the operands. 24561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (smi_operands) { 24571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2); 24581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 24591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block FloatingPointHelper::LoadOperands(masm, 24601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block destination, 24611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block heap_number_map, 24621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block scratch1, 24631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block scratch2, 24641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block not_numbers); 24651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 24661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 24671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Calculate the result. 24681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (destination == FloatingPointHelper::kVFPRegisters) { 24691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Using VFP registers: 24701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // d6: Left value 24711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // d7: Right value 24721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block CpuFeatures::Scope scope(VFP3); 24731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block switch (op_) { 24741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::ADD: 24751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vadd(d5, d6, d7); 24761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 24771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SUB: 24781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vsub(d5, d6, d7); 24791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 24801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::MUL: 24811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vmul(d5, d6, d7); 24821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 24831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::DIV: 24841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vdiv(d5, d6, d7); 24851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 24861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block default: 24871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block UNREACHABLE(); 24881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 24891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 24901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ sub(r0, result, Operand(kHeapObjectTag)); 24911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vstr(d5, r0, HeapNumber::kValueOffset); 24921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ add(r0, r0, Operand(kHeapObjectTag)); 24931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 24941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 2495e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Call the C function to handle the double operation. 2496e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch FloatingPointHelper::CallCCodeForDoubleOperation(masm, 2497e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch op_, 2498e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch result, 2499e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch1); 25008b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (FLAG_debug_code) { 25018b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ stop("Unreachable code."); 25028b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } 25031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 25041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 25051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 25061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_OR: 25071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_XOR: 25081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_AND: 25091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SAR: 25101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SHR: 25111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SHL: { 25121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (smi_operands) { 25131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiUntag(r3, left); 25141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiUntag(r2, right); 25151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 25161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Convert operands to 32-bit integers. Right in r2 and left in r3. 251744f0eee88ff00398ff7f715fab053374d808c90dSteve Block FloatingPointHelper::ConvertNumberToInt32(masm, 251844f0eee88ff00398ff7f715fab053374d808c90dSteve Block left, 251944f0eee88ff00398ff7f715fab053374d808c90dSteve Block r3, 252044f0eee88ff00398ff7f715fab053374d808c90dSteve Block heap_number_map, 252144f0eee88ff00398ff7f715fab053374d808c90dSteve Block scratch1, 252244f0eee88ff00398ff7f715fab053374d808c90dSteve Block scratch2, 252344f0eee88ff00398ff7f715fab053374d808c90dSteve Block scratch3, 252444f0eee88ff00398ff7f715fab053374d808c90dSteve Block d0, 252544f0eee88ff00398ff7f715fab053374d808c90dSteve Block not_numbers); 252644f0eee88ff00398ff7f715fab053374d808c90dSteve Block FloatingPointHelper::ConvertNumberToInt32(masm, 252744f0eee88ff00398ff7f715fab053374d808c90dSteve Block right, 252844f0eee88ff00398ff7f715fab053374d808c90dSteve Block r2, 252944f0eee88ff00398ff7f715fab053374d808c90dSteve Block heap_number_map, 253044f0eee88ff00398ff7f715fab053374d808c90dSteve Block scratch1, 253144f0eee88ff00398ff7f715fab053374d808c90dSteve Block scratch2, 253244f0eee88ff00398ff7f715fab053374d808c90dSteve Block scratch3, 253344f0eee88ff00398ff7f715fab053374d808c90dSteve Block d0, 253444f0eee88ff00398ff7f715fab053374d808c90dSteve Block not_numbers); 25351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 25361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 25371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label result_not_a_smi; 25381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block switch (op_) { 25391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_OR: 25401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ orr(r2, r3, Operand(r2)); 25411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 25421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_XOR: 25431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ eor(r2, r3, Operand(r2)); 25441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 25451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_AND: 25461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ and_(r2, r3, Operand(r2)); 25471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 25481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SAR: 25491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Use only the 5 least significant bits of the shift count. 25501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ GetLeastBitsFromInt32(r2, r2, 5); 25511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(r2, Operand(r3, ASR, r2)); 25521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 25531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SHR: 25541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Use only the 5 least significant bits of the shift count. 25551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ GetLeastBitsFromInt32(r2, r2, 5); 25561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(r2, Operand(r3, LSR, r2), SetCC); 25571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // SHR is special because it is required to produce a positive answer. 25581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // The code below for writing into heap numbers isn't capable of 25591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // writing the register as an unsigned int so we go to slow case if we 25601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // hit this case. 25618b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 25621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ b(mi, &result_not_a_smi); 25631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 25641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ b(mi, not_numbers); 25651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 25661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 25671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SHL: 25681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Use only the 5 least significant bits of the shift count. 25691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ GetLeastBitsFromInt32(r2, r2, 5); 25701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(r2, Operand(r3, LSL, r2)); 25711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 25721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block default: 25731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block UNREACHABLE(); 25741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 25751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 25761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check that the *signed* result fits in a smi. 25771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ add(r3, r2, Operand(0x40000000), SetCC); 25781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ b(mi, &result_not_a_smi); 25791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiTag(r0, r2); 25801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 25811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 25821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Allocate new heap number for result. 25831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&result_not_a_smi); 2584e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register result = r5; 2585e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (smi_operands) { 2586e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ AllocateHeapNumber( 2587e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch result, scratch1, scratch2, heap_number_map, gc_required); 2588e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { 2589e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateHeapResultAllocation( 2590e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch masm, result, heap_number_map, scratch1, scratch2, gc_required); 2591e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 25921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 25931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // r2: Answer as signed int32. 25941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // r5: Heap number to write answer into. 25951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 25961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Nothing can go wrong now, so move the heap number to r0, which is the 25971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // result. 25981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(r0, Operand(r5)); 25991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 26008b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 26011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Convert the int32 in r2 to the heap number in r0. r3 is corrupted. As 26021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // mentioned above SHR needs to always produce a positive result. 26031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block CpuFeatures::Scope scope(VFP3); 26041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vmov(s0, r2); 26051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (op_ == Token::SHR) { 26061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vcvt_f64_u32(d0, s0); 26071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 26081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vcvt_f64_s32(d0, s0); 26091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 26101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ sub(r3, r0, Operand(kHeapObjectTag)); 26111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ vstr(d0, r3, HeapNumber::kValueOffset); 26121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(); 26131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 26141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Tail call that writes the int32 in r2 to the heap number in r0, using 26151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // r3 as scratch. r0 is preserved and returned. 26161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block WriteInt32ToHeapNumberStub stub(r2, r0, r3); 26171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ TailCallStub(&stub); 26181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 26191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 26201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 26211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block default: 26221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block UNREACHABLE(); 26231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 26241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 26251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 26261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 26271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// Generate the smi code. If the operation on smis are successful this return is 26281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// generated. If the result is not a smi and heap number allocation is not 26291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// requested the code falls through. If number allocation is requested but a 26301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// heap number cannot be allocated the code jumps to the lable gc_required. 2631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiCode( 2632257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 26338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch Label* use_runtime, 26341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label* gc_required, 26351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { 26361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label not_smis; 26371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 26381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register left = r1; 26391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register right = r0; 26401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch1 = r7; 26411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 26421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Perform combined smi check on both operands. 26431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ orr(scratch1, left, Operand(right)); 26441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block STATIC_ASSERT(kSmiTag == 0); 26453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(scratch1, ¬_smis); 26461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 26471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // If the smi-smi operation results in a smi return is generated. 26481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateSmiSmiOperation(masm); 26491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 26501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // If heap number results are possible generate the result in an allocated 26511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // heap number. 26521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) { 26538b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch GenerateFPOperation(masm, true, use_runtime, gc_required); 26541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 26551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(¬_smis); 26561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 26571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 26581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 26601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label not_smis, call_runtime; 26611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (result_type_ == BinaryOpIC::UNINITIALIZED || 2663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch result_type_ == BinaryOpIC::SMI) { 26641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Only allow smi results. 26658b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch GenerateSmiCode(masm, &call_runtime, NULL, NO_HEAPNUMBER_RESULTS); 26661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 26671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Allow heap number result and don't make a transition if a heap number 26681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // cannot be allocated. 26698b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch GenerateSmiCode(masm, 26708b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch &call_runtime, 26718b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch &call_runtime, 26728b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch ALLOW_HEAPNUMBER_RESULTS); 26731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 26741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 26751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Code falls through if the result is not returned as either a smi or heap 26761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // number. 26771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateTypeTransition(masm); 26781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 26791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&call_runtime); 26801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateCallRuntime(masm); 26811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 26821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 26831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { 2685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(operands_type_ == BinaryOpIC::STRING); 26861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(op_ == Token::ADD); 26871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Try to add arguments as strings, otherwise, transition to the generic 2688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // BinaryOpIC type. 26891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateAddStrings(masm); 26901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateTypeTransition(masm); 26911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 26921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 26931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { 2695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label call_runtime; 2696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); 2697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(op_ == Token::ADD); 2698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If both arguments are strings, call the string add stub. 2699257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Otherwise, do a transition. 2700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 2702257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = r1; 2703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = r0; 2704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Test if left operand is a string. 2706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfSmi(left, &call_runtime); 2707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE); 2708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(ge, &call_runtime); 2709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2710257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Test if right operand is a string. 2711257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfSmi(right, &call_runtime); 2712257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE); 2713257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(ge, &call_runtime); 2714257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2715257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); 2716257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateRegisterArgsPush(masm); 2717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ TailCallStub(&string_add_stub); 2718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_runtime); 2720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateTypeTransition(masm); 2721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 2722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 2724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { 2725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(operands_type_ == BinaryOpIC::INT32); 27261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2727e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register left = r1; 2728e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register right = r0; 2729e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch1 = r7; 2730e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch2 = r9; 2731e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch DwVfpRegister double_scratch = d0; 2732e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch SwVfpRegister single_scratch = s3; 2733e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2734e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register heap_number_result = no_reg; 2735e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register heap_number_map = r6; 2736e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 2737e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2738e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label call_runtime; 2739e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Labels for type transition, used for wrong input or output types. 2740e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Both label are currently actually bound to the same position. We use two 2741e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // different label to differentiate the cause leading to type transition. 2742e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label transition; 2743e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2744e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Smi-smi fast case. 2745e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label skip; 2746e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ orr(scratch1, left, right); 2747e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ JumpIfNotSmi(scratch1, &skip); 2748e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateSmiSmiOperation(masm); 2749e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Fall through if the result is not a smi. 2750e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&skip); 2751e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2752e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch switch (op_) { 2753e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::ADD: 2754e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::SUB: 2755e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::MUL: 2756e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::DIV: 2757e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::MOD: { 27583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Load both operands and check that they are 32-bit integer. 27593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Jump to type transition if they are not. The registers r0 and r1 (right 27603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // and left) are preserved for the runtime call. 27613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch FloatingPointHelper::Destination destination = 27623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch (CpuFeatures::IsSupported(VFP3) && op_ != Token::MOD) 27633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch ? FloatingPointHelper::kVFPRegisters 27643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch : FloatingPointHelper::kCoreRegisters; 27653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 27663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch FloatingPointHelper::LoadNumberAsInt32Double(masm, 27673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch right, 27683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch destination, 27693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch d7, 27703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch r2, 27713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch r3, 27723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch heap_number_map, 27733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch scratch1, 27743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch scratch2, 27753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch s0, 27763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch &transition); 27773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch FloatingPointHelper::LoadNumberAsInt32Double(masm, 27783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch left, 27793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch destination, 27803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch d6, 27813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch r4, 27823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch r5, 27833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch heap_number_map, 27843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch scratch1, 27853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch scratch2, 27863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch s0, 27873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch &transition); 2788e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2789e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (destination == FloatingPointHelper::kVFPRegisters) { 2790e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch CpuFeatures::Scope scope(VFP3); 2791e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label return_heap_number; 2792e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch switch (op_) { 2793e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::ADD: 2794e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vadd(d5, d6, d7); 2795e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 2796e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::SUB: 2797e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vsub(d5, d6, d7); 2798e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 2799e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::MUL: 2800e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vmul(d5, d6, d7); 2801e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 2802e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::DIV: 2803e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vdiv(d5, d6, d7); 2804e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 2805e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch default: 2806e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch UNREACHABLE(); 2807e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 2808e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2809e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (op_ != Token::DIV) { 2810e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // These operations produce an integer result. 2811e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Try to return a smi if we can. 2812e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Otherwise return a heap number if allowed, or jump to type 2813e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // transition. 2814e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2815e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ EmitVFPTruncate(kRoundToZero, 2816e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch single_scratch, 2817e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch d5, 2818e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch1, 2819e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch2); 2820e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (result_type_ <= BinaryOpIC::INT32) { 2822e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // If the ne condition is set, result does 2823e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // not fit in a 32-bit integer. 2824e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(ne, &transition); 2825e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 2826e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2827e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Check if the result fits in a smi. 2828e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vmov(scratch1, single_scratch); 2829e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ add(scratch2, scratch1, Operand(0x40000000), SetCC); 2830e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // If not try to return a heap number. 2831e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(mi, &return_heap_number); 283244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Check for minus zero. Return heap number for minus zero. 283344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Label not_zero; 283469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(scratch1, Operand::Zero()); 283544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ b(ne, ¬_zero); 283644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ vmov(scratch2, d5.high()); 283744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ tst(scratch2, Operand(HeapNumber::kSignMask)); 283844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ b(ne, &return_heap_number); 283944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(¬_zero); 284044f0eee88ff00398ff7f715fab053374d808c90dSteve Block 2841e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Tag the result and return. 2842e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ SmiTag(r0, scratch1); 2843e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ret(); 284444f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 284544f0eee88ff00398ff7f715fab053374d808c90dSteve Block // DIV just falls through to allocating a heap number. 2846e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 2847e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 28483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&return_heap_number); 28493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Return a heap number, or fall through to type transition or runtime 28503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // call if we can't. 28513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (result_type_ >= ((op_ == Token::DIV) ? BinaryOpIC::HEAP_NUMBER 28523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch : BinaryOpIC::INT32)) { 2853e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // We are using vfp registers so r5 is available. 2854e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch heap_number_result = r5; 2855e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateHeapResultAllocation(masm, 2856e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch heap_number_result, 2857e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch heap_number_map, 2858e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch1, 2859e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch2, 2860e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch &call_runtime); 2861e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ sub(r0, heap_number_result, Operand(kHeapObjectTag)); 2862e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vstr(d5, r0, HeapNumber::kValueOffset); 2863e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(r0, heap_number_result); 2864e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ret(); 2865e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 2866e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2867e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // A DIV operation expecting an integer result falls through 2868e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // to type transition. 2869e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2870e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { 2871e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // We preserved r0 and r1 to be able to call runtime. 2872e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Save the left value on the stack. 2873e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Push(r5, r4); 2874e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2875053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block Label pop_and_call_runtime; 2876053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block 2877e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Allocate a heap number to store the result. 2878e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch heap_number_result = r5; 2879e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateHeapResultAllocation(masm, 2880e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch heap_number_result, 2881e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch heap_number_map, 2882e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch1, 2883e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch2, 2884053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block &pop_and_call_runtime); 2885e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2886e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Load the left value from the value saved on the stack. 2887e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Pop(r1, r0); 2888e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2889e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Call the C function to handle the double operation. 2890e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch FloatingPointHelper::CallCCodeForDoubleOperation( 2891e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch masm, op_, heap_number_result, scratch1); 28928b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (FLAG_debug_code) { 28938b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ stop("Unreachable code."); 28948b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } 2895053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block 2896053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ bind(&pop_and_call_runtime); 2897053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ Drop(2); 2898053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ b(&call_runtime); 2899e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 2900e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2901e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 2902e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 2903e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2904e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::BIT_OR: 2905e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::BIT_XOR: 2906e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::BIT_AND: 2907e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::SAR: 2908e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::SHR: 2909e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::SHL: { 2910e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label return_heap_number; 2911e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch3 = r5; 2912e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Convert operands to 32-bit integers. Right in r2 and left in r3. The 2913e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // registers r0 and r1 (right and left) are preserved for the runtime 2914e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // call. 2915e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch FloatingPointHelper::LoadNumberAsInt32(masm, 2916e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch left, 2917e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch r3, 2918e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch heap_number_map, 2919e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch1, 2920e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch2, 2921e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch3, 2922e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch d0, 2923e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch &transition); 2924e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch FloatingPointHelper::LoadNumberAsInt32(masm, 2925e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch right, 2926e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch r2, 2927e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch heap_number_map, 2928e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch1, 2929e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch2, 2930e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch3, 2931e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch d0, 2932e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch &transition); 2933e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2934e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // The ECMA-262 standard specifies that, for shift operations, only the 2935e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // 5 least significant bits of the shift value should be used. 2936e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch switch (op_) { 2937e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::BIT_OR: 2938e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ orr(r2, r3, Operand(r2)); 2939e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 2940e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::BIT_XOR: 2941e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ eor(r2, r3, Operand(r2)); 2942e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 2943e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::BIT_AND: 2944e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ and_(r2, r3, Operand(r2)); 2945e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 2946e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::SAR: 2947e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ and_(r2, r2, Operand(0x1f)); 2948e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(r2, Operand(r3, ASR, r2)); 2949e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 2950e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::SHR: 2951e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ and_(r2, r2, Operand(0x1f)); 2952e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(r2, Operand(r3, LSR, r2), SetCC); 2953e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // SHR is special because it is required to produce a positive answer. 2954e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // We only get a negative result if the shift value (r2) is 0. 2955e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // This result cannot be respresented as a signed 32-bit integer, try 2956e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // to return a heap number if we can. 2957e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // The non vfp3 code does not support this special case, so jump to 2958e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // runtime if we don't support it. 29598b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 2960257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(mi, (result_type_ <= BinaryOpIC::INT32) 2961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ? &transition 2962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch : &return_heap_number); 2963e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { 2964257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(mi, (result_type_ <= BinaryOpIC::INT32) 2965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ? &transition 2966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch : &call_runtime); 2967e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 2968e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 2969e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case Token::SHL: 2970e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ and_(r2, r2, Operand(0x1f)); 2971e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(r2, Operand(r3, LSL, r2)); 2972e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 2973e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch default: 2974e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch UNREACHABLE(); 2975e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 2976e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2977e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Check if the result fits in a smi. 2978e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ add(scratch1, r2, Operand(0x40000000), SetCC); 2979e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // If not try to return a heap number. (We know the result is an int32.) 2980e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(mi, &return_heap_number); 2981e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Tag the result and return. 2982e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ SmiTag(r0, r2); 2983e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ret(); 2984e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2985e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&return_heap_number); 29868b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch heap_number_result = r5; 29878b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch GenerateHeapResultAllocation(masm, 29888b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch heap_number_result, 29898b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch heap_number_map, 29908b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch scratch1, 29918b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch scratch2, 29928b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch &call_runtime); 2993e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 29948b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 29958b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch CpuFeatures::Scope scope(VFP3); 2996e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (op_ != Token::SHR) { 2997e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Convert the result to a floating point value. 2998e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vmov(double_scratch.low(), r2); 2999e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vcvt_f64_s32(double_scratch, double_scratch.low()); 3000e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { 3001e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // The result must be interpreted as an unsigned 32-bit integer. 3002e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vmov(double_scratch.low(), r2); 3003e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vcvt_f64_u32(double_scratch, double_scratch.low()); 3004e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 3005e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3006e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Store the result. 3007e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ sub(r0, heap_number_result, Operand(kHeapObjectTag)); 3008e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vstr(double_scratch, r0, HeapNumber::kValueOffset); 3009e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(r0, heap_number_result); 3010e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ret(); 3011e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { 3012e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Tail call that writes the int32 in r2 to the heap number in r0, using 3013e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // r3 as scratch. r0 is preserved and returned. 30148b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ mov(r0, r5); 3015e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch WriteInt32ToHeapNumberStub stub(r2, r0, r3); 3016e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ TailCallStub(&stub); 3017e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 3018e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3019e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 3020e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 3021e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3022e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch default: 3023e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch UNREACHABLE(); 3024e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 3025e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 30263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We never expect DIV to yield an integer result, so we always generate 30273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // type transition code for DIV operations expecting an integer result: the 30283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // code will fall through to this type transition. 30293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (transition.is_linked() || 30303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch ((op_ == Token::DIV) && (result_type_ <= BinaryOpIC::INT32))) { 3031e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&transition); 3032e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateTypeTransition(masm); 3033e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 3034e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3035e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&call_runtime); 3036e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateCallRuntime(masm); 30371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 30381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 30391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 3040257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { 304144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Label call_runtime; 30421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 304344f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (op_ == Token::ADD) { 304444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Handle string addition here, because it is the only operation 304544f0eee88ff00398ff7f715fab053374d808c90dSteve Block // that does not do a ToNumber conversion on the operands. 304644f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateAddStrings(masm); 304744f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 30481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 304944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Convert oddball arguments to numbers. 305044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Label check, done; 305144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CompareRoot(r1, Heap::kUndefinedValueRootIndex); 305244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ b(ne, &check); 305344f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (Token::IsBitOp(op_)) { 305444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(r1, Operand(Smi::FromInt(0))); 305544f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 305644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadRoot(r1, Heap::kNanValueRootIndex); 305744f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 305844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ jmp(&done); 305944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&check); 306044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CompareRoot(r0, Heap::kUndefinedValueRootIndex); 306144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ b(ne, &done); 306244f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (Token::IsBitOp(op_)) { 306344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(r0, Operand(Smi::FromInt(0))); 306444f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 306544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadRoot(r0, Heap::kNanValueRootIndex); 306644f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 306744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&done); 306844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 306944f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateHeapNumberStub(masm); 307044f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 307144f0eee88ff00398ff7f715fab053374d808c90dSteve Block 307244f0eee88ff00398ff7f715fab053374d808c90dSteve Block 3073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 307444f0eee88ff00398ff7f715fab053374d808c90dSteve Block Label call_runtime; 307544f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateFPOperation(masm, false, &call_runtime, &call_runtime); 30761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 30771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&call_runtime); 30781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateCallRuntime(masm); 30791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 30801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 30811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 3082257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { 3083e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label call_runtime, call_string_add_or_runtime; 30841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 30858b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch GenerateSmiCode(masm, &call_runtime, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 30861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 3087e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateFPOperation(masm, false, &call_string_add_or_runtime, &call_runtime); 30881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 3089e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&call_string_add_or_runtime); 30901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (op_ == Token::ADD) { 30911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateAddStrings(masm); 30921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 30931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 3094e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&call_runtime); 3095e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateCallRuntime(masm); 30961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 30971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 30981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 3099257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { 31001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(op_ == Token::ADD); 3101e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label left_not_string, call_runtime; 31021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 31031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register left = r1; 31041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register right = r0; 31051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 3106e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Check if left argument is a string. 3107e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ JumpIfSmi(left, &left_not_string); 31081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE); 3109e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(ge, &left_not_string); 3110e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3111e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); 3112e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateRegisterArgsPush(masm); 3113e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ TailCallStub(&string_add_left_stub); 31141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 3115e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Left operand is not a string, test right. 3116e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&left_not_string); 31171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfSmi(right, &call_runtime); 31181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE); 31191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ b(ge, &call_runtime); 31201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 3121e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); 31221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateRegisterArgsPush(masm); 3123e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ TailCallStub(&string_add_right_stub); 31241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 31251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // At least one argument is not a string. 31261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&call_runtime); 31271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 31281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 31291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 3130257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) { 31311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateRegisterArgsPush(masm); 31321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block switch (op_) { 31331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::ADD: 3134257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 31351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 31361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SUB: 3137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 31381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 31391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::MUL: 3140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 31411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 31421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::DIV: 3143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 31441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 31451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::MOD: 3146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 31471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 31481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_OR: 3149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 31501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 31511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_AND: 3152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 31531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 31541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::BIT_XOR: 3155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 31561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 31571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SAR: 3158257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 31591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 31601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SHR: 3161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 31621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 31631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case Token::SHL: 3164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 31651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 31661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block default: 31671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block UNREACHABLE(); 31681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 31691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 31701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 31711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 3172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm, 3173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register result, 3174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register heap_number_map, 3175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch1, 3176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch2, 3177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* gc_required) { 31781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Code below will scratch result if allocation fails. To keep both arguments 31791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // intact for the runtime call result cannot be one of these. 31801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(!result.is(r0) && !result.is(r1)); 31811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 31821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (mode_ == OVERWRITE_LEFT || mode_ == OVERWRITE_RIGHT) { 31831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label skip_allocation, allocated; 31841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register overwritable_operand = mode_ == OVERWRITE_LEFT ? r1 : r0; 31851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // If the overwritable operand is already an object, we skip the 31861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // allocation of a heap number. 31871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfNotSmi(overwritable_operand, &skip_allocation); 31881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Allocate a heap number for the result. 31891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ AllocateHeapNumber( 31901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block result, scratch1, scratch2, heap_number_map, gc_required); 31911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ b(&allocated); 31921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&skip_allocation); 31931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Use object holding the overwritable operand for result. 31941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(result, Operand(overwritable_operand)); 31951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&allocated); 31961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 31971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(mode_ == NO_OVERWRITE); 31981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ AllocateHeapNumber( 31991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block result, scratch1, scratch2, heap_number_map, gc_required); 32001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 32011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 32021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 3204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { 32051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Push(r1, r0); 3206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 3207b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3208b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 320980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::Generate(MacroAssembler* masm) { 3210e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Untagged case: double input in d2, double result goes 3211e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // into d2. 3212e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Tagged case: tagged input on top of stack and in r0, 3213e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // tagged result (heap number) goes into r0. 3214e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 321580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label input_not_smi; 321680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label loaded; 3217e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label calculate; 3218e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label invalid_cache; 3219e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch const Register scratch0 = r9; 3220e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch const Register scratch1 = r7; 3221e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch const Register cache_entry = r0; 3222e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch const bool tagged = (argument_type_ == TAGGED); 322380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 32248b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 322580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CpuFeatures::Scope scope(VFP3); 3226e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (tagged) { 3227e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Argument is a number and is on stack and in r0. 3228e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Load argument and check if it is a smi. 3229e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ JumpIfNotSmi(r0, &input_not_smi); 3230e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3231e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Input is a smi. Convert to double and load the low and high words 3232e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // of the double into r2, r3. 3233e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ IntegerToDoubleConversionWithVFP3(r0, r3, r2); 3234e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(&loaded); 3235e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3236e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&input_not_smi); 3237e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Check if input is a HeapNumber. 3238e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ CheckMap(r0, 3239e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch r1, 3240e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Heap::kHeapNumberMapRootIndex, 3241e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch &calculate, 3242257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch DONT_DO_SMI_CHECK); 3243e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Input is a HeapNumber. Load it to a double register and store the 3244e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // low and high words into r2, r3. 3245e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset)); 3246e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vmov(r2, r3, d0); 3247e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { 3248e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Input is untagged double in d2. Output goes to d2. 3249e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vmov(r2, r3, d2); 3250e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 325180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loaded); 325280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2 = low 32 bits of double value 325380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r3 = high 32 bits of double value 325480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compute hash (the shifts are arithmetic): 325580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); 325680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ eor(r1, r2, Operand(r3)); 325780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ eor(r1, r1, Operand(r1, ASR, 16)); 325880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ eor(r1, r1, Operand(r1, ASR, 8)); 325944f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize)); 326044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ And(r1, r1, Operand(TranscendentalCache::SubCache::kCacheSize - 1)); 326180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 326280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2 = low 32 bits of double value. 326380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r3 = high 32 bits of double value. 326480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1 = TranscendentalCache::hash(double value). 326544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate* isolate = masm->isolate(); 326644f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference cache_array = 326744f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::transcendental_cache_array_address(isolate); 326844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(cache_entry, Operand(cache_array)); 326944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // cache_entry points to cache array. 327044f0eee88ff00398ff7f715fab053374d808c90dSteve Block int cache_array_index 327144f0eee88ff00398ff7f715fab053374d808c90dSteve Block = type_ * sizeof(isolate->transcendental_cache()->caches_[0]); 327244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ ldr(cache_entry, MemOperand(cache_entry, cache_array_index)); 327380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0 points to the cache for the type type_. 327480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If NULL, the cache hasn't been initialized yet, so go through runtime. 3275e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cmp(cache_entry, Operand(0, RelocInfo::NONE)); 3276e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(eq, &invalid_cache); 327780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 327880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG 327980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the layout of cache elements match expectations. 328044f0eee88ff00398ff7f715fab053374d808c90dSteve Block { TranscendentalCache::SubCache::Element test_elem[2]; 328180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_start = reinterpret_cast<char*>(&test_elem[0]); 328280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); 328380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); 328480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); 328580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); 328680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. 328780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(0, elem_in0 - elem_start); 328880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(kIntSize, elem_in1 - elem_start); 328980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CHECK_EQ(2 * kIntSize, elem_out - elem_start); 329080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 329180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 329280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 329380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12]. 329480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r1, r1, Operand(r1, LSL, 1)); 3295e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ add(cache_entry, cache_entry, Operand(r1, LSL, 2)); 329680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if cache matches: Double value is stored in uint32_t[2] array. 3297e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit()); 329880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r2, r4); 32993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(r3, r5, eq); 3300e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(ne, &calculate); 3301e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Cache hit. Load result, cleanup and return. 33023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Counters* counters = masm->isolate()->counters(); 33033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ IncrementCounter( 33043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch counters->transcendental_cache_hit(), 1, scratch0, scratch1); 3305e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (tagged) { 3306e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Pop input value from stack and load result into r0. 3307e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ pop(); 3308e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(r0, Operand(r6)); 3309e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { 3310e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Load result into d2. 3311e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset)); 3312e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 3313e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ret(); 33148b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } // if (CpuFeatures::IsSupported(VFP3)) 3315e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3316e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&calculate); 33173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Counters* counters = masm->isolate()->counters(); 33183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ IncrementCounter( 33193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch counters->transcendental_cache_miss(), 1, scratch0, scratch1); 3320e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (tagged) { 3321e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&invalid_cache); 332244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference runtime_function = 332344f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference(RuntimeFunction(), masm->isolate()); 332444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ TailCallExternalReference(runtime_function, 1, 1); 3325e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { 33268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (!CpuFeatures::IsSupported(VFP3)) UNREACHABLE(); 3327e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch CpuFeatures::Scope scope(VFP3); 3328e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3329e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label no_update; 3330e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label skip_cache; 3331e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3332e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Call C function to calculate the result and update the cache. 3333e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Register r0 holds precalculated cache entry address; preserve 3334e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // it on the stack and pop it into register cache_entry after the 3335e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // call. 3336e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ push(cache_entry); 3337e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateCallCFunction(masm, scratch0); 3338e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ GetCFunctionDoubleResult(d2); 3339e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3340e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Try to update the cache. If we cannot allocate a 3341e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // heap number, we return the result without updating. 3342e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ pop(cache_entry); 3343e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex); 3344e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ AllocateHeapNumber(r6, scratch0, scratch1, r5, &no_update); 3345e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vstr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset)); 3346e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ stm(ia, cache_entry, r2.bit() | r3.bit() | r6.bit()); 3347e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ret(); 3348e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3349e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&invalid_cache); 3350e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // The cache is invalid. Call runtime which will recreate the 3351e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // cache. 3352e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex); 3353e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ AllocateHeapNumber(r0, scratch0, scratch1, r5, &skip_cache); 3354e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vstr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset)); 33553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 33563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FrameScope scope(masm, StackFrame::INTERNAL); 33573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(r0); 33583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallRuntime(RuntimeFunction(), 1); 33593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 3360e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ vldr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset)); 3361e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Ret(); 3362e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3363e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&skip_cache); 3364e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Call C function to calculate the result and answer directly 3365e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // without updating the cache. 3366e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateCallCFunction(masm, scratch0); 3367e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ GetCFunctionDoubleResult(d2); 3368e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&no_update); 3369e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3370e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // We return the value in d2 without adding it to the cache, but 3371e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // we cause a scavenging GC so that future allocations will succeed. 33723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 33733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FrameScope scope(masm, StackFrame::INTERNAL); 33743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 33753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Allocate an aligned object larger than a HeapNumber. 33763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(4 * kPointerSize >= HeapNumber::kSize); 33773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(scratch0, Operand(4 * kPointerSize)); 33783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(scratch0); 33793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); 33803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 338180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 338280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 3383e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch} 338480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3385e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 3386e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm, 3387e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch) { 338844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate* isolate = masm->isolate(); 338944f0eee88ff00398ff7f715fab053374d808c90dSteve Block 3390e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ push(lr); 3391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ PrepareCallCFunction(0, 1, scratch); 3392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (masm->use_eabi_hardfloat()) { 3393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ vmov(d0, d2); 3394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 3395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ vmov(r0, r1, d2); 3396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 33973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch AllowExternalCallThatCantCauseGC scope(masm); 3398e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch switch (type_) { 3399e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case TranscendentalCache::SIN: 3400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallCFunction(ExternalReference::math_sin_double_function(isolate), 3401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 0, 1); 3402e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 3403e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case TranscendentalCache::COS: 3404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallCFunction(ExternalReference::math_cos_double_function(isolate), 3405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 0, 1); 3406e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 34073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch case TranscendentalCache::TAN: 34083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallCFunction(ExternalReference::math_tan_double_function(isolate), 34093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 0, 1); 34103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch break; 3411e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch case TranscendentalCache::LOG: 3412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallCFunction(ExternalReference::math_log_double_function(isolate), 3413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 0, 1); 3414e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 3415e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch default: 3416e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch UNIMPLEMENTED(); 3417e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch break; 3418e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 3419e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ pop(lr); 342080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 342180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 342280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 342380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian MonsenRuntime::FunctionId TranscendentalCacheStub::RuntimeFunction() { 342480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen switch (type_) { 342580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Add more cases when necessary. 342680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case TranscendentalCache::SIN: return Runtime::kMath_sin; 342780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case TranscendentalCache::COS: return Runtime::kMath_cos; 34283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch case TranscendentalCache::TAN: return Runtime::kMath_tan; 3429b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch case TranscendentalCache::LOG: return Runtime::kMath_log; 343080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen default: 343180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen UNIMPLEMENTED(); 343280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return Runtime::kAbort; 343380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 343480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 343580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 343680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 343780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StackCheckStub::Generate(MacroAssembler* masm) { 3438f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch __ TailCallRuntime(Runtime::kStackGuard, 0, 1); 343980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 344080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 344180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 34423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid InterruptStub::Generate(MacroAssembler* masm) { 34433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kInterrupt, 0, 1); 34443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 34455d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch 34465d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch 34473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid MathPowStub::Generate(MacroAssembler* masm) { 34483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CpuFeatures::Scope vfp3_scope(VFP3); 34493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const Register base = r1; 34503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const Register exponent = r2; 34513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const Register heapnumbermap = r5; 34523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const Register heapnumber = r0; 34533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const DoubleRegister double_base = d1; 34543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const DoubleRegister double_exponent = d2; 34553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const DoubleRegister double_result = d3; 34563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const DoubleRegister double_scratch = d0; 34573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const SwVfpRegister single_scratch = s0; 34583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const Register scratch = r9; 34593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const Register scratch2 = r7; 34603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 34613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label call_runtime, done, int_exponent; 34623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (exponent_type_ == ON_STACK) { 34633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label base_is_smi, unpack_exponent; 34643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // The exponent and base are supplied as arguments on the stack. 34653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // This can only happen if the stub is called from non-optimized code. 34663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load input parameters from stack to double registers. 346744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ ldr(base, MemOperand(sp, 1 * kPointerSize)); 346844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ ldr(exponent, MemOperand(sp, 0 * kPointerSize)); 346944f0eee88ff00398ff7f715fab053374d808c90dSteve Block 34703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex); 347144f0eee88ff00398ff7f715fab053374d808c90dSteve Block 34723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ UntagAndJumpIfSmi(scratch, base, &base_is_smi); 347344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ ldr(scratch, FieldMemOperand(base, JSObject::kMapOffset)); 347444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(scratch, heapnumbermap); 347544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ b(ne, &call_runtime); 34763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 347744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ vldr(double_base, FieldMemOperand(base, HeapNumber::kValueOffset)); 34783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&unpack_exponent); 347944f0eee88ff00398ff7f715fab053374d808c90dSteve Block 34803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&base_is_smi); 34813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vmov(single_scratch, scratch); 34823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vcvt_f64_s32(double_base, single_scratch); 34833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&unpack_exponent); 34843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 34853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent); 348644f0eee88ff00398ff7f715fab053374d808c90dSteve Block 348744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ ldr(scratch, FieldMemOperand(exponent, JSObject::kMapOffset)); 348844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(scratch, heapnumbermap); 348944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ b(ne, &call_runtime); 349044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ vldr(double_exponent, 349144f0eee88ff00398ff7f715fab053374d808c90dSteve Block FieldMemOperand(exponent, HeapNumber::kValueOffset)); 34923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else if (exponent_type_ == TAGGED) { 34933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Base is already in double_base. 34943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent); 34953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 34963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vldr(double_exponent, 34973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FieldMemOperand(exponent, HeapNumber::kValueOffset)); 34983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 34993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 35003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (exponent_type_ != INTEGER) { 35013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label int_exponent_convert; 35023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Detect integer exponents stored as double. 35033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vcvt_u32_f64(single_scratch, double_exponent); 35043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // We do not check for NaN or Infinity here because comparing numbers on 35053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ARM correctly distinguishes NaNs. We end up calling the built-in. 35063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vcvt_f64_u32(double_scratch, single_scratch); 35073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ VFPCompareAndSetFlags(double_scratch, double_exponent); 35083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &int_exponent_convert); 35093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 35103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (exponent_type_ == ON_STACK) { 35113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Detect square root case. Crankshaft detects constant +/-0.5 at 35123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // compile time and uses DoMathPowHalf instead. We then skip this check 35133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // for non-constant cases of +/-0.5 as these hardly occur. 35143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label not_plus_half; 35153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 35163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Test for 0.5. 35173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vmov(double_scratch, 0.5); 35183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ VFPCompareAndSetFlags(double_exponent, double_scratch); 35193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, ¬_plus_half); 35203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 35213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Calculates square root of base. Check for the special case of 35223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13). 35233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vmov(double_scratch, -V8_INFINITY); 35243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ VFPCompareAndSetFlags(double_base, double_scratch); 35253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vneg(double_result, double_scratch, eq); 35263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &done); 35273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 35283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Add +0 to convert -0 to +0. 35293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vadd(double_scratch, double_base, kDoubleRegZero); 35303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vsqrt(double_result, double_scratch); 35313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&done); 35323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 35333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(¬_plus_half); 35343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vmov(double_scratch, -0.5); 35353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ VFPCompareAndSetFlags(double_exponent, double_scratch); 35363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &call_runtime); 35373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 35383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Calculates square root of base. Check for the special case of 35393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13). 35403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vmov(double_scratch, -V8_INFINITY); 35413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ VFPCompareAndSetFlags(double_base, double_scratch); 35423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vmov(double_result, kDoubleRegZero, eq); 35433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &done); 35443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 35453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Add +0 to convert -0 to +0. 35463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vadd(double_scratch, double_base, kDoubleRegZero); 35473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vmov(double_result, 1); 35483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vsqrt(double_scratch, double_scratch); 35493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vdiv(double_result, double_result, double_scratch); 35503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&done); 35513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 355244f0eee88ff00398ff7f715fab053374d808c90dSteve Block 355344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ push(lr); 35543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 35553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch AllowExternalCallThatCantCauseGC scope(masm); 35563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ PrepareCallCFunction(0, 2, scratch); 35573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ SetCallCDoubleArguments(double_base, double_exponent); 35583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallCFunction( 35593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference::power_double_double_function(masm->isolate()), 35603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 0, 2); 35613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 3562c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ pop(lr); 3563c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ GetCFunctionDoubleResult(double_result); 35643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&done); 35653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 35663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&int_exponent_convert); 35673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vcvt_u32_f64(single_scratch, double_exponent); 35683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vmov(scratch, single_scratch); 35693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 35703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 35713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Calculate power with integer exponent. 35723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&int_exponent); 35733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 35743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Get two copies of exponent in the registers scratch and exponent. 35753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (exponent_type_ == INTEGER) { 35763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(scratch, exponent); 35773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 35783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Exponent has previously been stored into scratch as untagged integer. 35793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(exponent, scratch); 35803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 35813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vmov(double_scratch, double_base); // Back up base. 35823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vmov(double_result, 1.0); 35833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 35843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Get absolute value of exponent. 35853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(scratch, Operand(0)); 35863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(scratch2, Operand(0), LeaveCC, mi); 35873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(scratch, scratch2, scratch, LeaveCC, mi); 35883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 35893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label while_true; 35903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&while_true); 35913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(scratch, Operand(scratch, ASR, 1), SetCC); 35923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vmul(double_result, double_result, double_scratch, cs); 35933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vmul(double_scratch, double_scratch, double_scratch, ne); 35943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &while_true); 35953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 35963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(exponent, Operand(0)); 35973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ge, &done); 35983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vmov(double_scratch, 1.0); 35993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vdiv(double_result, double_scratch, double_result); 36003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Test whether result is zero. Bail out to check for subnormal result. 36013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. 36023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ VFPCompareAndSetFlags(double_result, 0.0); 36033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &done); 36043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // double_exponent may not containe the exponent value if the input was a 36053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // smi. We set it with exponent value before bailing out. 36063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vmov(single_scratch, exponent); 36073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ vcvt_f64_s32(double_exponent, single_scratch); 36083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 36093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Returning or bailing out. 36103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Counters* counters = masm->isolate()->counters(); 36113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (exponent_type_ == ON_STACK) { 36123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // The arguments are still on the stack. 36133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&call_runtime); 36143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); 36153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 36163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // The stub is called from non-optimized code, which expects the result 36173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // as heap number in exponent. 36183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&done); 36193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateHeapNumber( 36203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch heapnumber, scratch, scratch2, heapnumbermap, &call_runtime); 362144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ vstr(double_result, 362244f0eee88ff00398ff7f715fab053374d808c90dSteve Block FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); 36233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(heapnumber.is(r0)); 36243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2); 36253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(2); 36263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 36273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(lr); 36283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 36293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch AllowExternalCallThatCantCauseGC scope(masm); 36303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ PrepareCallCFunction(0, 2, scratch); 36313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ SetCallCDoubleArguments(double_base, double_exponent); 36323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallCFunction( 36333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference::power_double_double_function(masm->isolate()), 36343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 0, 2); 36353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 36363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(lr); 36373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ GetCFunctionDoubleResult(double_result); 363885b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch 36393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&done); 36403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2); 36413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(); 36423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 364344f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 364444f0eee88ff00398ff7f715fab053374d808c90dSteve Block 364544f0eee88ff00398ff7f715fab053374d808c90dSteve Block 364644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool CEntryStub::NeedsImmovableCode() { 364744f0eee88ff00398ff7f715fab053374d808c90dSteve Block return true; 364844f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 364944f0eee88ff00398ff7f715fab053374d808c90dSteve Block 365044f0eee88ff00398ff7f715fab053374d808c90dSteve Block 36513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool CEntryStub::IsPregenerated() { 36523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return (!save_doubles_ || ISOLATE->fp_stubs_generated()) && 36533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch result_size_ == 1; 36543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 36553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 36563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 36573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CodeStub::GenerateStubsAheadOfTime() { 36583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CEntryStub::GenerateAheadOfTime(); 36593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(); 36603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(); 36613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch RecordWriteStub::GenerateFixedRegStubsAheadOfTime(); 36623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 36633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 36643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 36653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CodeStub::GenerateFPStubs() { 36663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CEntryStub save_doubles(1, kSaveFPRegs); 36673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Handle<Code> code = save_doubles.GetCode(); 36683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch code->set_is_pregenerated(true); 36693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch StoreBufferOverflowStub stub(kSaveFPRegs); 36703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch stub.GetCode()->set_is_pregenerated(true); 36713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch code->GetIsolate()->set_fp_stubs_generated(true); 3672592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch} 3673592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch 3674592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch 36753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CEntryStub::GenerateAheadOfTime() { 36763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CEntryStub stub(1, kDontSaveFPRegs); 36773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Handle<Code> code = stub.GetCode(); 36783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch code->set_is_pregenerated(true); 3679592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch} 3680592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch 3681592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch 368280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateCore(MacroAssembler* masm, 368380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_normal_exception, 368480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_termination_exception, 368580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* throw_out_of_memory_exception, 368680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool do_gc, 36871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block bool always_allocate) { 368880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0: result parameter for PerformGC, if any 368980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r4: number of arguments including receiver (C callee-saved) 369080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r5: pointer to builtin function (C callee-saved) 369180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r6: pointer to the first argument (C callee-saved) 369244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate* isolate = masm->isolate(); 369380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 369480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (do_gc) { 369580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Passing r0. 3696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ PrepareCallCFunction(1, 0, r1); 3697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallCFunction(ExternalReference::perform_gc_function(isolate), 3698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1, 0); 369980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 370080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 370180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference scope_depth = 370244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::heap_always_allocate_scope_depth(isolate); 370380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (always_allocate) { 370480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(scope_depth)); 370580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r1, MemOperand(r0)); 370680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r1, r1, Operand(1)); 370780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r1, MemOperand(r0)); 370880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 370980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 371080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call C built-in. 371180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0 = argc, r1 = argv 371280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(r4)); 371380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r1, Operand(r6)); 371480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 37151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block#if defined(V8_HOST_ARCH_ARM) 371680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int frame_alignment = MacroAssembler::ActivationFrameAlignment(); 371780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int frame_alignment_mask = frame_alignment - 1; 371880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 371980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (frame_alignment > kPointerSize) { 372080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label alignment_as_expected; 372180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(IsPowerOf2(frame_alignment)); 37221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ tst(sp, Operand(frame_alignment_mask)); 372380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &alignment_as_expected); 372480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Don't use Check here, as it will call Runtime_Abort re-entering here. 372580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ stop("Unexpected alignment"); 372680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&alignment_as_expected); 372780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 372880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 372980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 373080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 373144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(r2, Operand(ExternalReference::isolate_address())); 373244f0eee88ff00398ff7f715fab053374d808c90dSteve Block 37333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // To let the GC traverse the return address of the exit frames, we need to 37343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // know where the return address is. The CEntryStub is unmovable, so 37353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // we can store the address on the stack to be able to find it again and 37363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // we never have to restore it, because it will not change. 37371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Compute the return address in lr to return to after the jump below. Pc is 37381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // already at '+ 8' from the current instruction but return is after three 37391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // instructions so add another 4 to pc to get the return address. 37401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block masm->add(lr, pc, Operand(4)); 37411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ str(lr, MemOperand(sp, 0)); 37421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block masm->Jump(r5); 374380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 374480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (always_allocate) { 374580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1 374680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // though (contain the result). 374780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r2, Operand(scope_depth)); 374880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, MemOperand(r2)); 374980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(r3, r3, Operand(1)); 375080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r3, MemOperand(r2)); 375180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 375280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 375380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // check for failure result 375480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label failure_returned; 375580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); 375680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Lower 2 bits of r2 are 0 iff r0 has failure tag. 375780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r2, r0, Operand(1)); 375880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(r2, Operand(kFailureTagMask)); 375980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &failure_returned); 376080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 376180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Exit C frame and return. 376280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0:r1: result 376380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // sp: stack pointer 376480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // fp: frame pointer 3765e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Callee-saved register r4 still holds argc. 3766e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LeaveExitFrame(save_doubles_, r4); 3767e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(pc, lr); 376880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 376980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // check if we should retry or throw exception 377080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label retry; 377180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&failure_returned); 377280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); 377380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); 377480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &retry); 377580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 377680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Special handling of out of memory exceptions. 377780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Failure* out_of_memory = Failure::OutOfMemoryException(); 377880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory))); 377980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, throw_out_of_memory_exception); 378080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 378180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Retrieve the pending exception and clear the variable. 37823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r3, Operand(isolate->factory()->the_hole_value())); 3783589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, 378444f0eee88ff00398ff7f715fab053374d808c90dSteve Block isolate))); 378580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, MemOperand(ip)); 378680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r3, MemOperand(ip)); 378780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 378880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Special handling of termination exceptions which are uncatchable 378980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // by javascript code. 379044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(r0, Operand(isolate->factory()->termination_exception())); 379180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, throw_termination_exception); 379280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 379380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle normal exception. 379480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(throw_normal_exception); 379580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 379680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&retry); // pass last failure (r0) as parameter (r0) when retrying 379780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 379880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 379980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 380080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::Generate(MacroAssembler* masm) { 380180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Called from JavaScript; parameters are on stack as if calling JS function 380280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0: number of arguments including receiver 380380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1: pointer to builtin function 380480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // fp: frame pointer (restored after C call) 380580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // sp: stack pointer (restored as callee's sp after C call) 380680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // cp: current context (C callee-saved) 380780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 380880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result returned in r0 or r0+r1 by default. 380980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 381080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NOTE: Invocations of builtins may return failure objects 381180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // instead of a proper result. The builtin entry handles 381280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // this by performing a garbage collection and retrying the 381380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // builtin once. 381480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 38151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Compute the argv pointer in a callee-saved register. 38161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ add(r6, sp, Operand(r0, LSL, kPointerSizeLog2)); 38171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ sub(r6, r6, Operand(kPointerSize)); 38181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 381980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Enter the exit frame that transitions from JavaScript to C++. 38203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FrameScope scope(masm, StackFrame::MANUAL); 3821b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ EnterExitFrame(save_doubles_); 382280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 38233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up argc and the builtin function in callee-saved registers. 38241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(r4, Operand(r0)); 38251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(r5, Operand(r1)); 38261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 382780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r4: number of arguments (C callee-saved) 382880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r5: pointer to builtin function (C callee-saved) 382980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r6: pointer to first argument (C callee-saved) 383080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 383180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_normal_exception; 383280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_termination_exception; 383380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label throw_out_of_memory_exception; 383480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 383580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call into the runtime system. 383680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 383780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 383880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 383980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 384080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen false, 38411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block false); 384280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 384380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do space-specific GC and retry runtime call. 384480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 384580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 384680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 384780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 384880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen true, 38491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block false); 385080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 385180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do full GC and retry runtime call one final time. 385280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Failure* failure = Failure::InternalError(); 385380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(reinterpret_cast<int32_t>(failure))); 385480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateCore(masm, 385580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_normal_exception, 385680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_termination_exception, 385780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &throw_out_of_memory_exception, 385880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen true, 38591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block true); 386080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 386180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_out_of_memory_exception); 38623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set external caught exception to false. 38633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Isolate* isolate = masm->isolate(); 38643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress, 38653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch isolate); 38663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r0, Operand(false, RelocInfo::NONE)); 38673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r2, Operand(external_caught)); 38683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r0, MemOperand(r2)); 38693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 38703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set pending exception and r0 to out of memory exception. 38713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Failure* out_of_memory = Failure::OutOfMemoryException(); 38723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory))); 38733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress, 38743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch isolate))); 38753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r0, MemOperand(r2)); 38763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Fall through to the next label. 387780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 387880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_termination_exception); 38793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ThrowUncatchable(r0); 388080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 388180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&throw_normal_exception); 38823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Throw(r0); 388380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 388480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 388580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 388680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { 388780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0: code entry 388880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1: function 388980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: receiver 389080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r3: argc 389180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // [sp+0]: argv 389280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 38933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label invoke, handler_entry, exit; 389480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 389580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Called from C, so do not pop argc and args on exit (preserve sp) 389680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // No need to save register-passed args 389780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Save callee-saved registers (incl. cp and fp), sp, and lr 389880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ stm(db_w, sp, kCalleeSaved | lr.bit()); 389980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 39007d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 39017d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch CpuFeatures::Scope scope(VFP3); 39027d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch // Save callee-saved vfp registers. 39037d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch __ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg); 39043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Set up the reserved register for 0.0. 39053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ vmov(kDoubleRegZero, 0.0); 39067d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch } 39077d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch 390880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get address of argv, see stm above. 390980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0: code entry 391080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1: function 391180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: receiver 391280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r3: argc 39137d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch 39143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up argv in r4. 39157d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize; 39167d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 39177d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch offset_to_argv += kNumDoubleCalleeSaved * kDoubleSize; 39187d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch } 39197d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch __ ldr(r4, MemOperand(sp, offset_to_argv)); 392080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 392180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Push a frame with special values setup to mark it as an entry frame. 392280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0: code entry 392380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1: function 392480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: receiver 392580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r3: argc 392680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r4: argv 392744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate* isolate = masm->isolate(); 392880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r8, Operand(-1)); // Push a bad frame pointer to fail if it is used. 392980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; 393080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r7, Operand(Smi::FromInt(marker))); 393180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r6, Operand(Smi::FromInt(marker))); 393244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(r5, 3933589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate))); 393480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r5, MemOperand(r5)); 393580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Push(r8, r7, r6, r5); 393680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 39373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up frame pointer for the frame to be pushed. 393880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); 393980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 3940b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // If this is the outermost JS call, set js_entry_sp value. 3941053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block Label non_outermost_js; 3942589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate); 3943b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(r5, Operand(ExternalReference(js_entry_sp))); 3944b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ldr(r6, MemOperand(r5)); 394569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(r6, Operand::Zero()); 3946053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ b(ne, &non_outermost_js); 3947053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ str(fp, MemOperand(r5)); 3948053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ mov(ip, Operand(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); 3949053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block Label cont; 3950053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ b(&cont); 3951053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ bind(&non_outermost_js); 3952053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ mov(ip, Operand(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME))); 3953053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ bind(&cont); 3954053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ push(ip); 3955b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 39563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Jump to a faked try block that does the invoke, with a faked catch 39573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // block that sets the pending exception. 39583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&invoke); 39593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&handler_entry); 39603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch handler_offset_ = handler_entry.pos(); 39613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Caught exception: Store result (exception) in the pending exception 39623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // field in the JSEnv and return a failure sentinel. Coming in here the 39633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // fp will be invalid because the PushTryHandler below sets it to 0 to 39643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // signal the existence of the JSEntry frame. 3965589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, 396644f0eee88ff00398ff7f715fab053374d808c90dSteve Block isolate))); 396780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r0, MemOperand(ip)); 396880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception()))); 396980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(&exit); 397080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 39713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Invoke: Link this frame into the handler chain. There's only one 39723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // handler block in this code object, so its index is 0. 397380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&invoke); 397480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Must preserve r0-r4, r5-r7 are available. 39753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ PushTryHandler(StackHandler::JS_ENTRY, 0); 397680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If an exception not caught by another handler occurs, this handler 397780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // returns control to the code after the bl(&invoke) above, which 397880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // restores all kCalleeSaved registers (including cp and fp) to their 397980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // saved values before returning a failure to C. 398080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 398180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Clear any pending exceptions. 39823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r5, Operand(isolate->factory()->the_hole_value())); 3983589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, 398444f0eee88ff00398ff7f715fab053374d808c90dSteve Block isolate))); 398580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r5, MemOperand(ip)); 398680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 398780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Invoke the function by calling through JS entry trampoline builtin. 398880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Notice that we cannot store a reference to the trampoline code directly in 398980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // this stub, because runtime stubs are not traversed when doing GC. 399080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 399180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Expected registers by Builtins::JSEntryTrampoline 399280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0: code entry 399380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1: function 399480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: receiver 399580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r3: argc 399680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r4: argv 399780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (is_construct) { 399844f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline, 399944f0eee88ff00398ff7f715fab053374d808c90dSteve Block isolate); 400080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ip, Operand(construct_entry)); 400180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 400244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference entry(Builtins::kJSEntryTrampoline, isolate); 400380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(ip, Operand(entry)); 400480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 400580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(ip, MemOperand(ip)); // deref address 400680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 400780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Branch and link to JSEntryTrampoline. We don't use the double underscore 400880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // macro for the add instruction because we don't want the coverage tool 400980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // inserting instructions here after we read the pc. 401080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(lr, Operand(pc)); 401180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen masm->add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); 401280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4013053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block // Unlink this frame from the handler chain. 4014053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ PopTryHandler(); 401580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4016053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ bind(&exit); // r0 holds result 4017053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block // Check if the current stack frame is marked as the outermost JS frame. 4018053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block Label non_outermost_js_2; 4019053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ pop(r5); 4020053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ cmp(r5, Operand(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); 4021053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ b(ne, &non_outermost_js_2); 402269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(r6, Operand::Zero()); 4023b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(r5, Operand(ExternalReference(js_entry_sp))); 4024053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ str(r6, MemOperand(r5)); 4025053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block __ bind(&non_outermost_js_2); 402680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 402780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore the top frame descriptors from the stack. 402880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(r3); 402944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(ip, 4030589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate))); 403180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r3, MemOperand(ip)); 403280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 403380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Reset the stack to the callee saved registers. 403480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); 403580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 403680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Restore callee-saved registers and return. 403780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG 403880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 403980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(lr, Operand(pc)); 404080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 404180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif 40427d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch 40437d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 40447d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch CpuFeatures::Scope scope(VFP3); 40457d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch // Restore callee-saved vfp registers. 40467d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg); 40477d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch } 40487d3e7fc4b65010eabe860313ee0c64f50843f6e3Ben Murdoch 404980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldm(ia_w, sp, kCalleeSaved | pc.bit()); 405080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 405180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 405280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 40531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// Uses registers r0 to r4. 40541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// Expected input (depending on whether args are in registers or on the stack): 40551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// * object: r0 or at sp + 1 * kPointerSize. 40561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// * function: r1 or at sp. 40571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// 40581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// An inlined call site may have been generated before calling this stub. 40591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// In this case the offset to the inline site to patch is passed on the stack, 40601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// in the safepoint slot for register r4. 40611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// (See LCodeGen::DoInstanceOfKnownGlobal) 406280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid InstanceofStub::Generate(MacroAssembler* masm) { 40631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Call site inlining and patching implies arguments in registers. 40641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck()); 40651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // ReturnTrueFalse is only implemented for inlined call sites. 40661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(!ReturnTrueFalseObject() || HasCallSiteInlineCheck()); 40671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 4068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fixed register usage throughout the stub: 40699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const Register object = r0; // Object (lhs). 40701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register map = r3; // Map of the object. 40719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const Register function = r1; // Function (rhs). 4072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const Register prototype = r4; // Prototype of the function. 40731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block const Register inline_site = r9; 4074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const Register scratch = r2; 40751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 40763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int32_t kDeltaToLoadBoolResult = 4 * kPointerSize; 40771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 4078b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label slow, loop, is_instance, is_not_instance, not_js_object; 40791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 4080086aeeaae12517475c22695a200be45495516549Ben Murdoch if (!HasArgsInRegisters()) { 40819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ldr(object, MemOperand(sp, 1 * kPointerSize)); 40829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ldr(function, MemOperand(sp, 0)); 4083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 408480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check that the left hand is a JS object and load map. 40861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfSmi(object, ¬_js_object); 40879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); 408880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 40891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // If there is a call site cache don't look in the global cache, but do the 40901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // real lookup and update the call site cache. 40911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (!HasCallSiteInlineCheck()) { 40921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label miss; 40933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(function, Heap::kInstanceofCacheFunctionRootIndex); 40941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ b(ne, &miss); 40953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(map, Heap::kInstanceofCacheMapRootIndex); 40961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ b(ne, &miss); 40971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ LoadRoot(r0, Heap::kInstanceofCacheAnswerRootIndex); 40981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(HasArgsInRegisters() ? 0 : 2); 40991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 41001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&miss); 41011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 410280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 41031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Get the prototype of the function. 41043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true); 410580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 410680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the function prototype is a JS object. 41071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfSmi(prototype, &slow); 4108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); 410980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 41101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Update the global instanceof or call site inlined cache with the current 41111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // map and function. The cached answer will be set when it is known below. 41121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (!HasCallSiteInlineCheck()) { 41131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); 41141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex); 41151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 41161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(HasArgsInRegisters()); 41171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Patch the (relocated) inlined map check. 41181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 41191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // The offset was stored in r4 safepoint slot. 41201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // (See LCodeGen::DoDeferredLInstanceOfKnownGlobal) 4121e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LoadFromSafepointRegisterSlot(scratch, r4); 41221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ sub(inline_site, lr, scratch); 41231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Get the map location in scratch and patch it. 41241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ GetRelocatedValueLocation(inline_site, scratch); 41253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(scratch, MemOperand(scratch)); 41263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(map, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); 41271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 412880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 412980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Register mapping: r3 is object map and r4 is function prototype. 413080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get prototype of object into r2. 4131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ldr(scratch, FieldMemOperand(map, Map::kPrototypeOffset)); 413280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 41331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // We don't need map any more. Use it as a scratch register. 41341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch2 = map; 41351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block map = no_reg; 41361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 413780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Loop through the prototype chain looking for the function prototype. 41381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ LoadRoot(scratch2, Heap::kNullValueRootIndex); 413980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 4140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(scratch, Operand(prototype)); 414180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &is_instance); 41421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ cmp(scratch, scratch2); 414380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &is_not_instance); 4144b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ldr(scratch, FieldMemOperand(scratch, HeapObject::kMapOffset)); 4145b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ldr(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset)); 414680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&loop); 414780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 414880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&is_instance); 41491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (!HasCallSiteInlineCheck()) { 41501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(r0, Operand(Smi::FromInt(0))); 41511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex); 41521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 41531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Patch the call site to return true. 41541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ LoadRoot(r0, Heap::kTrueValueRootIndex); 41551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ add(inline_site, inline_site, Operand(kDeltaToLoadBoolResult)); 41561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Get the boolean result location in scratch and patch it. 41571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ GetRelocatedValueLocation(inline_site, scratch); 41581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ str(r0, MemOperand(scratch)); 41591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 41601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (!ReturnTrueFalseObject()) { 41611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(r0, Operand(Smi::FromInt(0))); 41621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 41631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 4164086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Ret(HasArgsInRegisters() ? 0 : 2); 416580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 416680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&is_not_instance); 41671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (!HasCallSiteInlineCheck()) { 41681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(r0, Operand(Smi::FromInt(1))); 41691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex); 41701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 41711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Patch the call site to return false. 41721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ LoadRoot(r0, Heap::kFalseValueRootIndex); 41731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ add(inline_site, inline_site, Operand(kDeltaToLoadBoolResult)); 41741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Get the boolean result location in scratch and patch it. 41751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ GetRelocatedValueLocation(inline_site, scratch); 41761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ str(r0, MemOperand(scratch)); 41771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 41781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (!ReturnTrueFalseObject()) { 41791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ mov(r0, Operand(Smi::FromInt(1))); 41801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 41811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 4182086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Ret(HasArgsInRegisters() ? 0 : 2); 4183b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4184b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label object_not_null, object_not_null_or_smi; 4185b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(¬_js_object); 4186b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Before null, smi and string value checks, check that the rhs is a function 4187b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // as for a non-function rhs an exception needs to be thrown. 41881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfSmi(function, &slow); 41891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CompareObjectType(function, scratch2, scratch, JS_FUNCTION_TYPE); 4190b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ b(ne, &slow); 4191b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4192b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Null is not instance of anything. 4193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(scratch, Operand(masm->isolate()->factory()->null_value())); 4194b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ b(ne, &object_not_null); 4195b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(r0, Operand(Smi::FromInt(1))); 4196086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Ret(HasArgsInRegisters() ? 0 : 2); 4197b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4198b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&object_not_null); 4199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Smi values are not instances of anything. 42001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfNotSmi(object, &object_not_null_or_smi); 4201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(r0, Operand(Smi::FromInt(1))); 4202086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Ret(HasArgsInRegisters() ? 0 : 2); 4203b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 4204b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&object_not_null_or_smi); 4205b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // String values are not instances of anything. 4206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ IsObjectJSStringType(object, scratch, &slow); 4207b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(r0, Operand(Smi::FromInt(1))); 4208086aeeaae12517475c22695a200be45495516549Ben Murdoch __ Ret(HasArgsInRegisters() ? 0 : 2); 420980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 421080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case. Tail call builtin. 4211086aeeaae12517475c22695a200be45495516549Ben Murdoch __ bind(&slow); 42121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (!ReturnTrueFalseObject()) { 42131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (HasArgsInRegisters()) { 42141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Push(r0, r1); 42151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 4216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 42171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 42183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 42193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FrameScope scope(masm, StackFrame::INTERNAL); 42203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Push(r0, r1); 42213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); 42223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 422369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(r0, Operand::Zero()); 42241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ LoadRoot(r0, Heap::kTrueValueRootIndex, eq); 42251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ LoadRoot(r0, Heap::kFalseValueRootIndex, ne); 42261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Ret(HasArgsInRegisters() ? 0 : 2); 42279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 422880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 422980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 423080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 42311e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockRegister InstanceofStub::left() { return r0; } 42321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 42331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 42341e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockRegister InstanceofStub::right() { return r1; } 42351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 42361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 423780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { 423880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // The displacement is the offset of the last parameter (if any) 423980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // relative to the frame pointer. 42403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kDisplacement = 424180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StandardFrameConstants::kCallerSPOffset - kPointerSize; 424280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 424380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the key is a smi. 424480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label slow; 42451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfNotSmi(r1, &slow); 424680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 424780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the calling frame is an arguments adaptor frame. 424880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label adaptor; 424980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 425080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset)); 425180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 425280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &adaptor); 425380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 425480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check index against formal parameters count limit passed in 425580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // through register r0. Use unsigned comparison to get negative 425680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // check for free. 425780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r1, r0); 4258086aeeaae12517475c22695a200be45495516549Ben Murdoch __ b(hs, &slow); 425980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 426080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the argument from the stack and return it. 426180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(r3, r0, r1); 426280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r3, fp, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); 426380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, MemOperand(r3, kDisplacement)); 426480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Jump(lr); 426580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 426680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Arguments adaptor case: Check index against actual arguments 426780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // limit found in the arguments adaptor frame. Use unsigned 426880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // comparison to get negative check for free. 426980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&adaptor); 427080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset)); 427180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r1, r0); 427280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(cs, &slow); 427380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 427480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the argument from the adaptor frame and return it. 427580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(r3, r0, r1); 427680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); 427780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, MemOperand(r3, kDisplacement)); 427880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Jump(lr); 427980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 428080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case: Handle non-smi or out-of-bounds access to arguments 428180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // by calling the runtime system. 428280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 428380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(r1); 428480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); 428580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 428680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 428780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 42883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { 428980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // sp[0] : number of parameters 429080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // sp[4] : receiver displacement 429180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // sp[8] : function 429280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 429380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the calling frame is an arguments adaptor frame. 42943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label runtime; 42953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 42963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r2, MemOperand(r3, StandardFrameConstants::kContextOffset)); 42973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(r2, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 42983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ b(ne, &runtime); 42993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Patch the arguments.length and the parameters pointer in the current frame. 43013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r2, MemOperand(r3, ArgumentsAdaptorFrameConstants::kLengthOffset)); 43023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r2, MemOperand(sp, 0 * kPointerSize)); 43033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r3, r3, Operand(r2, LSL, 1)); 43043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset)); 43053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r3, MemOperand(sp, 1 * kPointerSize)); 43063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&runtime); 43083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); 43093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch} 43103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { 43133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Stack layout: 43143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // sp[0] : number of parameters (tagged) 43153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // sp[4] : address of receiver argument 43163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // sp[8] : function 43173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Registers used over whole function: 43183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r6 : allocated object (tagged) 43193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r9 : mapped parameter count (tagged) 43203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); 43223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r1 = parameter count (tagged) 43233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Check if the calling frame is an arguments adaptor frame. 43253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label runtime; 43263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label adaptor_frame, try_allocate; 43273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 43283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r2, MemOperand(r3, StandardFrameConstants::kContextOffset)); 43293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(r2, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 43303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ b(eq, &adaptor_frame); 43313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // No adaptor, parameter count = argument count. 43333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(r2, r1); 43343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ b(&try_allocate); 43353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We have an adaptor frame. Patch the parameters pointer. 43373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&adaptor_frame); 43383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r2, MemOperand(r3, ArgumentsAdaptorFrameConstants::kLengthOffset)); 43393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r3, r3, Operand(r2, LSL, 1)); 43403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset)); 43413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r3, MemOperand(sp, 1 * kPointerSize)); 43423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r1 = parameter count (tagged) 43443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r2 = argument count (tagged) 43453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Compute the mapped parameter count = min(r1, r2) in r1. 43463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(r1, Operand(r2)); 43473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(r1, Operand(r2), LeaveCC, gt); 43483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&try_allocate); 43503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Compute the sizes of backing store, parameter map, and arguments object. 43523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 1. Parameter map, has 2 extra words containing context and backing store. 43533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int kParameterMapHeaderSize = 43543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch FixedArray::kHeaderSize + 2 * kPointerSize; 43553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // If there are no mapped parameters, we do not need the parameter_map. 43563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(r1, Operand(Smi::FromInt(0))); 435769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(r9, Operand::Zero(), LeaveCC, eq); 43583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(r9, Operand(r1, LSL, 1), LeaveCC, ne); 43593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r9, r9, Operand(kParameterMapHeaderSize), LeaveCC, ne); 43603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 2. Backing store. 43623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r9, r9, Operand(r2, LSL, 1)); 43633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r9, r9, Operand(FixedArray::kHeaderSize)); 43643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // 3. Arguments object. 43663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r9, r9, Operand(Heap::kArgumentsObjectSize)); 43673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Do the allocation of all three objects in one go. 43693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ AllocateInNewSpace(r9, r0, r3, r4, &runtime, TAG_OBJECT); 43703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r0 = address of new object(s) (tagged) 43723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r2 = argument count (tagged) 43733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Get the arguments boilerplate from the current (global) context into r4. 43743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int kNormalOffset = 43753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX); 43763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int kAliasedOffset = 43773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX); 43783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r4, MemOperand(r8, Context::SlotOffset(Context::GLOBAL_INDEX))); 43803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r4, FieldMemOperand(r4, GlobalObject::kGlobalContextOffset)); 438169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(r1, Operand::Zero()); 43823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r4, MemOperand(r4, kNormalOffset), eq); 43833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r4, MemOperand(r4, kAliasedOffset), ne); 43843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r0 = address of new object (tagged) 43863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r1 = mapped parameter count (tagged) 43873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r2 = argument count (tagged) 43883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r4 = address of boilerplate object (tagged) 43893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy the JS object part. 43903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { 43913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r3, FieldMemOperand(r4, i)); 43923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r3, FieldMemOperand(r0, i)); 43933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch } 43943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 43953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up the callee in-object property. 43963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); 43973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r3, MemOperand(sp, 2 * kPointerSize)); 43983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int kCalleeOffset = JSObject::kHeaderSize + 43993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsCalleeIndex * kPointerSize; 44003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r3, FieldMemOperand(r0, kCalleeOffset)); 44013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 44023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Use the length (smi tagged) and set that as an in-object property too. 44033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); 44043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch const int kLengthOffset = JSObject::kHeaderSize + 44053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsLengthIndex * kPointerSize; 44063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r2, FieldMemOperand(r0, kLengthOffset)); 44073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 44083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up the elements pointer in the allocated arguments object. 44093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // If we allocated a parameter map, r4 will point there, otherwise 44103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // it will point to the backing store. 44113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r4, r0, Operand(Heap::kArgumentsObjectSize)); 44123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset)); 44133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 44143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r0 = address of new object (tagged) 44153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r1 = mapped parameter count (tagged) 44163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r2 = argument count (tagged) 44173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r4 = address of parameter map or backing store (tagged) 44183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Initialize parameter map. If there are no mapped arguments, we're done. 44193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label skip_parameter_map; 44203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(r1, Operand(Smi::FromInt(0))); 44213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Move backing store address to r3, because it is 44223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // expected there when filling in the unmapped arguments. 44233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(r3, r4, LeaveCC, eq); 44243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ b(eq, &skip_parameter_map); 44253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 44263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ LoadRoot(r6, Heap::kNonStrictArgumentsElementsMapRootIndex); 44273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r6, FieldMemOperand(r4, FixedArray::kMapOffset)); 44283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r6, r1, Operand(Smi::FromInt(2))); 44293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r6, FieldMemOperand(r4, FixedArray::kLengthOffset)); 44303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r8, FieldMemOperand(r4, FixedArray::kHeaderSize + 0 * kPointerSize)); 44313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r6, r4, Operand(r1, LSL, 1)); 44323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r6, r6, Operand(kParameterMapHeaderSize)); 44333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r6, FieldMemOperand(r4, FixedArray::kHeaderSize + 1 * kPointerSize)); 44343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 44353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy the parameter slots and the holes in the arguments. 44363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We need to fill in mapped_parameter_count slots. They index the context, 44373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // where parameters are stored in reverse order, at 44383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 44393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // The mapped parameter thus need to get indices 44403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS+parameter_count-1 .. 44413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count 44423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // We loop from right to left. 44433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label parameters_loop, parameters_test; 44443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(r6, r1); 44453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r9, MemOperand(sp, 0 * kPointerSize)); 44463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r9, r9, Operand(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); 44473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(r9, r9, Operand(r1)); 44483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ LoadRoot(r7, Heap::kTheHoleValueRootIndex); 44493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r3, r4, Operand(r6, LSL, 1)); 44503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r3, r3, Operand(kParameterMapHeaderSize)); 44513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 44523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r6 = loop variable (tagged) 44533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r1 = mapping index (tagged) 44543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r3 = address of backing store (tagged) 44553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r4 = address of parameter map (tagged) 44563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r5 = temporary scratch (a.o., for address calculation) 44573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r7 = the hole value 44583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(¶meters_test); 44593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 44603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(¶meters_loop); 44613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(r6, r6, Operand(Smi::FromInt(1))); 44623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(r5, Operand(r6, LSL, 1)); 44633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r5, r5, Operand(kParameterMapHeaderSize - kHeapObjectTag)); 44643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r9, MemOperand(r4, r5)); 44653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(r5, r5, Operand(kParameterMapHeaderSize - FixedArray::kHeaderSize)); 44663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r7, MemOperand(r3, r5)); 44673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r9, r9, Operand(Smi::FromInt(1))); 44683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(¶meters_test); 44693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(r6, Operand(Smi::FromInt(0))); 44703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ b(ne, ¶meters_loop); 44713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 44723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&skip_parameter_map); 44733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r2 = argument count (tagged) 44743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r3 = address of backing store (tagged) 44753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // r5 = scratch 44763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Copy arguments header and remaining slots (if there are any). 44773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ LoadRoot(r5, Heap::kFixedArrayMapRootIndex); 44783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r5, FieldMemOperand(r3, FixedArray::kMapOffset)); 44793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r2, FieldMemOperand(r3, FixedArray::kLengthOffset)); 44803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 44813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Label arguments_loop, arguments_test; 44823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(r9, r1); 44833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r4, MemOperand(sp, 1 * kPointerSize)); 44843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(r4, r4, Operand(r9, LSL, 1)); 44853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ jmp(&arguments_test); 44863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 44873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&arguments_loop); 44883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ sub(r4, r4, Operand(kPointerSize)); 44893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r6, MemOperand(r4, 0)); 44903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r5, r3, Operand(r9, LSL, 1)); 44913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r6, FieldMemOperand(r5, FixedArray::kHeaderSize)); 44923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r9, r9, Operand(Smi::FromInt(1))); 44933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 44943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&arguments_test); 44953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ cmp(r9, Operand(r2)); 44963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ b(lt, &arguments_loop); 44973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 44983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Return and remove the on-stack parameters. 44993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(sp, sp, Operand(3 * kPointerSize)); 45003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ Ret(); 45013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 45023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Do the runtime call to allocate the arguments object. 45033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r2 = argument count (tagged) 45043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ bind(&runtime); 45053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ str(r2, MemOperand(sp, 0 * kPointerSize)); // Patch argument count. 45063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); 45073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch} 45083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 45093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch 45103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { 45113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // sp[0] : number of parameters 45123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // sp[4] : receiver displacement 45133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // sp[8] : function 45143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Check if the calling frame is an arguments adaptor frame. 451580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label adaptor_frame, try_allocate, runtime; 451680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 451780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset)); 451880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 451980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &adaptor_frame); 452080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 452180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the length from the frame. 452280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r1, MemOperand(sp, 0)); 452380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(&try_allocate); 452480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 452580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Patch the arguments.length and the parameters pointer. 452680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&adaptor_frame); 452780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r1, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset)); 452880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r1, MemOperand(sp, 0)); 452980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r3, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); 453080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset)); 453180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r3, MemOperand(sp, 1 * kPointerSize)); 453280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 453380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try the new space allocation. Start out with computing the size 453480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // of the arguments object and the elements array in words. 453580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label add_arguments_object; 453680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&try_allocate); 45379ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ cmp(r1, Operand(0, RelocInfo::NONE)); 453880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &add_arguments_object); 453980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r1, Operand(r1, LSR, kSmiTagSize)); 454080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r1, r1, Operand(FixedArray::kHeaderSize / kPointerSize)); 454180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&add_arguments_object); 45423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r1, r1, Operand(Heap::kArgumentsObjectSizeStrict / kPointerSize)); 454380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 454480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the allocation of both objects in one go. 45453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ AllocateInNewSpace(r1, 45463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch r0, 45473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch r2, 45483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch r3, 45493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch &runtime, 45503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch static_cast<AllocationFlags>(TAG_OBJECT | 45513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch SIZE_IN_WORDS)); 455280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 455380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the arguments boilerplate from the current (global) context. 455480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r4, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); 455580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r4, FieldMemOperand(r4, GlobalObject::kGlobalContextOffset)); 45563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ ldr(r4, MemOperand(r4, Context::SlotOffset( 45573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX))); 455880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 455980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy the JS object part. 456080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CopyFields(r0, r4, r3.bit(), JSObject::kHeaderSize / kPointerSize); 456180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 456280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the length (smi tagged) and set that as an in-object property too. 456344f0eee88ff00398ff7f715fab053374d808c90dSteve Block STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); 456480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); 456544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ str(r1, FieldMemOperand(r0, JSObject::kHeaderSize + 45663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch Heap::kArgumentsLengthIndex * kPointerSize)); 456780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 456880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If there are no actual arguments, we're done. 456980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label done; 45709ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ cmp(r1, Operand(0, RelocInfo::NONE)); 457180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &done); 457280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 457380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the parameters pointer from the stack. 457480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r2, MemOperand(sp, 1 * kPointerSize)); 457580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 45763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up the elements pointer in the allocated arguments object and 457780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // initialize the header in the elements fixed array. 45783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ add(r4, r0, Operand(Heap::kArgumentsObjectSizeStrict)); 457980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset)); 458080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(r3, Heap::kFixedArrayMapRootIndex); 458180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r3, FieldMemOperand(r4, FixedArray::kMapOffset)); 458280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r1, FieldMemOperand(r4, FixedArray::kLengthOffset)); 45833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Untag the length for the loop. 45843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ mov(r1, Operand(r1, LSR, kSmiTagSize)); 458580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 458680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy the fixed array slots. 458780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label loop; 45883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set up r4 to point to the first array slot. 458980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r4, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 459080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 459180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Pre-decrement r2 with kPointerSize on each iteration. 459280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Pre-decrement in order to skip receiver. 459380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, MemOperand(r2, kPointerSize, NegPreIndex)); 459480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Post-increment r4 with kPointerSize on each iteration. 459580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r3, MemOperand(r4, kPointerSize, PostIndex)); 459680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(r1, r1, Operand(1)); 45979ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ cmp(r1, Operand(0, RelocInfo::NONE)); 459880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &loop); 459980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 460080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return and remove the on-stack parameters. 460180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 460280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(sp, sp, Operand(3 * kPointerSize)); 460380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 460480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 460580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the runtime call to allocate the arguments object. 460680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 46073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); 460880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 460980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 461080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 461180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid RegExpExecStub::Generate(MacroAssembler* masm) { 461280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump directly to runtime if native RegExp is not selected at compile 461380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // time or if regexp entry in generated code is turned off runtime switch or 461480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // at compilation. 461580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef V8_INTERPRETED_REGEXP 461680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 461780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else // V8_INTERPRETED_REGEXP 461880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 461980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 462080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // sp[0]: last_match_info (expected JSArray) 462180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // sp[4]: previous index 462280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // sp[8]: subject string 462380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // sp[12]: JSRegExp object 462480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 46253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kLastMatchInfoOffset = 0 * kPointerSize; 46263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kPreviousIndexOffset = 1 * kPointerSize; 46273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kSubjectOffset = 2 * kPointerSize; 46283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kJSRegExpOffset = 3 * kPointerSize; 462980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 463080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime, invoke_regexp; 463180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 463280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocation of registers for this function. These are in callee save 463380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // registers and will be preserved by the call to the native RegExp code, as 463480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // this code is called using the normal C calling convention. When calling 463580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // directly from generated code the native RegExp code will not do a GC and 463680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // therefore the content of these registers are safe to use after the call. 463780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register subject = r4; 463880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register regexp_data = r5; 463980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register last_match_info_elements = r6; 464080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 464180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Ensure that a RegExp stack is allocated. 464244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate* isolate = masm->isolate(); 464380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference address_of_regexp_stack_memory_address = 464444f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_regexp_stack_memory_address(isolate); 464580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference address_of_regexp_stack_memory_size = 464644f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_regexp_stack_memory_size(isolate); 464780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(address_of_regexp_stack_memory_size)); 464880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, MemOperand(r0, 0)); 46493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(r0, Operand(0)); 465080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &runtime); 465180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 465280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the first argument is a JSRegExp object. 465380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, MemOperand(sp, kJSRegExpOffset)); 465480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 46553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(r0, &runtime); 465680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); 465780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &runtime); 465880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 465980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the RegExp has been compiled (data contains a fixed array). 466080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset)); 466180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (FLAG_debug_code) { 466280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(regexp_data, Operand(kSmiTagMask)); 46631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Check(ne, "Unexpected type for RegExp data, FixedArray expected"); 466480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE); 466580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Check(eq, "Unexpected type for RegExp data, FixedArray expected"); 466680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 466780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 466880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // regexp_data: RegExp data (FixedArray) 466980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. 467080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); 467180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r0, Operand(Smi::FromInt(JSRegExp::IRREGEXP))); 467280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &runtime); 467380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 467480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // regexp_data: RegExp data (FixedArray) 467580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the number of captures fit in the static offsets vector buffer. 467680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r2, 467780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); 467880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate number of capture registers (number_of_captures + 1) * 2. This 467980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // uses the asumption that smis are 2 * their untagged value. 468080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 468180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 468280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r2, r2, Operand(2)); // r2 was a smi. 468380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the static offsets vector buffer is large enough. 468480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r2, Operand(OffsetsVector::kStaticOffsetsVectorSize)); 468580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(hi, &runtime); 468680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 468780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: Number of capture registers 468880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // regexp_data: RegExp data (FixedArray) 468980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the second argument is a string. 469080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(subject, MemOperand(sp, kSubjectOffset)); 46913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(subject, &runtime); 469280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Condition is_string = masm->IsObjectStringType(subject, r0); 469380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(NegateCondition(is_string), &runtime); 469480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the length of the string to r3. 469580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, FieldMemOperand(subject, String::kLengthOffset)); 469680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 469780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: Number of capture registers 469880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r3: Length of subject string as a smi 469980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // subject: Subject string 470080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // regexp_data: RegExp data (FixedArray) 470180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the third argument is a positive smi less than the subject 470280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // string length. A negative value will be greater (unsigned comparison). 470380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, MemOperand(sp, kPreviousIndexOffset)); 47043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(r0, &runtime); 470580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r3, Operand(r0)); 470680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ls, &runtime); 470780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 470880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: Number of capture registers 470980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // subject: Subject string 471080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // regexp_data: RegExp data (FixedArray) 471180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the fourth object is a JSArray object. 471280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, MemOperand(sp, kLastMatchInfoOffset)); 47133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(r0, &runtime); 471480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE); 471580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &runtime); 471680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the JSArray is in fast case. 471780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(last_match_info_elements, 471880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldMemOperand(r0, JSArray::kElementsOffset)); 471980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset)); 47203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(r0, Heap::kFixedArrayMapRootIndex); 472180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &runtime); 472280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the last match info has space for the capture registers and the 472380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // additional information. 472480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, 472580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset)); 472680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r2, r2, Operand(RegExpImpl::kLastMatchOverhead)); 472780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r2, Operand(r0, ASR, kSmiTagSize)); 472880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(gt, &runtime); 472980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 473069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Reset offset for possibly sliced string. 473169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(r9, Operand(0)); 473280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // subject: Subject string 473380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // regexp_data: RegExp data (FixedArray) 473480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the representation and encoding of the subject string. 473580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label seq_string; 473680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); 473780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); 47383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // First check for flat string. None of the following string type tests will 47393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // succeed if subject is not a string or a short external string. 47403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(r1, 47413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r0, 47423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Operand(kIsNotStringMask | 47433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kStringRepresentationMask | 47443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kShortExternalStringMask), 47453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch SetCC); 474680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); 474780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &seq_string); 474880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 474980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // subject: Subject string 475080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // regexp_data: RegExp data (FixedArray) 47513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r1: whether subject is a string and if yes, its string representation 475269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Check for flat cons string or sliced string. 475380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // A flat cons string is a cons string where the second part is the empty 475480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // string. In that case the subject string is just the first part of the cons 475580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // string. Also in this case the first part of the cons string is known to be 475680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // a sequential string or an external string. 475769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // In the case of a sliced string its offset has to be taken into account. 47583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label cons_string, external_string, check_encoding; 475969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kConsStringTag < kExternalStringTag); 476069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); 47613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); 47623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); 476369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ cmp(r1, Operand(kExternalStringTag)); 476469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ b(lt, &cons_string); 47653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &external_string); 47663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 47673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Catch non-string subject or short external string. 47683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); 47693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ tst(r1, Operand(kIsNotStringMask | kShortExternalStringMask)); 47703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &runtime); 477169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 477269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // String is sliced. 477369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ldr(r9, FieldMemOperand(subject, SlicedString::kOffsetOffset)); 477469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(r9, Operand(r9, ASR, kSmiTagSize)); 477569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ ldr(subject, FieldMemOperand(subject, SlicedString::kParentOffset)); 477669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // r9: offset of sliced string, smi-tagged. 477769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ jmp(&check_encoding); 477869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // String is a cons string, check whether it is flat. 477969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&cons_string); 478080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset)); 47813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(r0, Heap::kEmptyStringRootIndex); 478280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &runtime); 478380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); 478469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Is first part of cons or parent of slice a flat string? 478569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&check_encoding); 478680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); 478780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); 478880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSeqStringTag == 0); 478980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(r0, Operand(kStringRepresentationMask)); 47903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &external_string); 47913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 479280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&seq_string); 479380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // subject: Subject string 479480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // regexp_data: RegExp data (FixedArray) 479580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0: Instance type of subject string 479680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(4 == kAsciiStringTag); 479780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kTwoByteStringTag == 0); 479880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find the code object based on the assumptions above. 479980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(r0, r0, Operand(kStringEncodingMask)); 480080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r3, Operand(r0, ASR, 2), SetCC); 480180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset), ne); 480280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset), eq); 480380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 480480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the irregexp code has been generated for the actual string 480580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // encoding. If it has, the field contains a code object otherwise it contains 4806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // a smi (code flushing support). 4807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfSmi(r7, &runtime); 480880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 480944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // r3: encoding of subject string (1 if ASCII, 0 if two_byte); 481080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r7: code 481180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // subject: Subject string 481280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // regexp_data: RegExp data (FixedArray) 481380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load used arguments before starting to push arguments for call to native 481480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // RegExp code to avoid handling changing stack height. 481580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r1, MemOperand(sp, kPreviousIndexOffset)); 481680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r1, Operand(r1, ASR, kSmiTagSize)); 481780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 481880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1: previous index 481944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // r3: encoding of subject string (1 if ASCII, 0 if two_byte); 482080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r7: code 482180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // subject: Subject string 482280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // regexp_data: RegExp data (FixedArray) 482380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // All checks done. Now push arguments for native regexp code. 482444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(isolate->counters()->regexp_entry_native(), 1, r0, r2); 482580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 482644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Isolates: note we add an additional parameter here (isolate pointer). 48273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kRegExpExecuteArguments = 8; 48283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kParameterRegisters = 4; 4829e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters); 4830e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 4831e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Stack pointer now points to cell where return address is to be written. 4832e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Arguments are before that on the stack or in registers. 483380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 483444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Argument 8 (sp[16]): Pass current isolate address. 483544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(r0, Operand(ExternalReference::isolate_address())); 483644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ str(r0, MemOperand(sp, 4 * kPointerSize)); 483744f0eee88ff00398ff7f715fab053374d808c90dSteve Block 4838e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Argument 7 (sp[12]): Indicate that this is a direct call from JavaScript. 483980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(1)); 4840e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ str(r0, MemOperand(sp, 3 * kPointerSize)); 484180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4842e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Argument 6 (sp[8]): Start (high end) of backtracking stack memory area. 484380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(address_of_regexp_stack_memory_address)); 484480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, MemOperand(r0, 0)); 484580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r2, Operand(address_of_regexp_stack_memory_size)); 484680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r2, MemOperand(r2, 0)); 484780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r0, r0, Operand(r2)); 4848e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ str(r0, MemOperand(sp, 2 * kPointerSize)); 484980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 4850e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Argument 5 (sp[4]): static offsets vector buffer. 485144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ mov(r0, 485244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Operand(ExternalReference::address_of_static_offsets_vector(isolate))); 4853e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ str(r0, MemOperand(sp, 1 * kPointerSize)); 485480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 485580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // For arguments 4 and 3 get string length, calculate start of string data and 485680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // calculate the shift of the index (0 for ASCII and 1 for two byte). 48573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r8, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag)); 485880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ eor(r3, r3, Operand(1)); 485969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Load the length from the original subject string from the previous stack 486069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // frame. Therefore we have to use fp, which points exactly to two pointer 486169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // sizes below the previous sp. (Because creating a new stack frame pushes 486269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // the previous fp onto the stack and moves up sp by 2 * kPointerSize.) 4863589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); 486469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // If slice offset is not 0, load the length from the original sliced string. 486569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Argument 4, r3: End of string data 486669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Argument 3, r2: Start of string data 486769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Prepare start and end index of the input. 486869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ add(r9, r8, Operand(r9, LSL, r3)); 486980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r2, r9, Operand(r1, LSL, r3)); 487069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 4871589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ ldr(r8, FieldMemOperand(subject, String::kLengthOffset)); 487269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(r8, Operand(r8, ASR, kSmiTagSize)); 487369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ add(r3, r9, Operand(r8, LSL, r3)); 487480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 487580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 2 (r1): Previous index. 487680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Already there 487780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 487880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Argument 1 (r0): Subject string. 4879589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ mov(r0, subject); 488080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 488180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate the code entry and call it. 488280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag)); 4883e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch DirectCEntryStub stub; 4884e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch stub.GenerateCall(masm, r7); 4885e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 4886e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ LeaveExitFrame(false, no_reg); 488780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 488880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0: result 488980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // subject: subject string (callee saved) 489080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // regexp_data: RegExp data (callee saved) 489180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // last_match_info_elements: Last match info elements (callee saved) 489280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 489380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check the result. 489480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label success; 4895e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 4896589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ cmp(r0, Operand(NativeRegExpMacroAssembler::SUCCESS)); 489780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &success); 489880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label failure; 4899589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE)); 490080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &failure); 4901589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ cmp(r0, Operand(NativeRegExpMacroAssembler::EXCEPTION)); 490280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If not exception it can only be retry. Handle that in the runtime system. 490380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &runtime); 490480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Result must now be exception. If there is no pending exception already a 490580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stack overflow (on the backtrack stack) was detected in RegExp code but 490680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // haven't created the exception yet. Handle that in the runtime system. 490780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // TODO(592): Rerunning the RegExp to get the stack overflow exception. 49083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r1, Operand(isolate->factory()->the_hole_value())); 4909589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress, 491044f0eee88ff00398ff7f715fab053374d808c90dSteve Block isolate))); 4911e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ldr(r0, MemOperand(r2, 0)); 4912589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ cmp(r0, r1); 491380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &runtime); 4914e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 4915e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ str(r1, MemOperand(r2, 0)); // Clear pending exception. 4916e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 4917e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Check if the exception is a termination. If so, throw as uncatchable. 4918589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ CompareRoot(r0, Heap::kTerminationExceptionRootIndex); 4919589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 4920e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label termination_exception; 4921e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(eq, &termination_exception); 4922e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 49233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Throw(r0); 4924e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 4925e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&termination_exception); 49263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ThrowUncatchable(r0); 4927e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 492880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&failure); 492980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // For failure and exception return null. 4930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, Operand(masm->isolate()->factory()->null_value())); 493180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(sp, sp, Operand(4 * kPointerSize)); 493280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 493380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 493480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Process the result from the native regexp code. 493580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&success); 493680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r1, 493780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); 493880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate number of capture registers (number_of_captures + 1) * 2. 493980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 494080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 494180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r1, r1, Operand(2)); // r1 was a smi. 494280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 494380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1: number of capture registers 494480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r4: subject string 494580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store the capture count. 494680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r2, Operand(r1, LSL, kSmiTagSize + kSmiShiftSize)); // To smi. 494780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r2, FieldMemOperand(last_match_info_elements, 494880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen RegExpImpl::kLastCaptureCountOffset)); 494980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store last subject and last input. 495080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(subject, 495180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldMemOperand(last_match_info_elements, 495280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen RegExpImpl::kLastSubjectOffset)); 49533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r2, subject); 49543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ RecordWriteField(last_match_info_elements, 49553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch RegExpImpl::kLastSubjectOffset, 49563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r2, 49573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r7, 49583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kLRHasNotBeenSaved, 49593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kDontSaveFPRegs); 496080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(subject, 496180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen FieldMemOperand(last_match_info_elements, 496280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen RegExpImpl::kLastInputOffset)); 49633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ RecordWriteField(last_match_info_elements, 49643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch RegExpImpl::kLastInputOffset, 49653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch subject, 49663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r7, 49673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kLRHasNotBeenSaved, 49683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kDontSaveFPRegs); 496980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 497080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the static offsets vector filled by the native regexp code. 497180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ExternalReference address_of_static_offsets_vector = 497244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::address_of_static_offsets_vector(isolate); 497380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r2, Operand(address_of_static_offsets_vector)); 497480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 497580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1: number of capture registers 497680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: offsets vector 497780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label next_capture, done; 497880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Capture register counter starts from number of capture registers and 497980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // counts down until wraping after zero. 498080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r0, 498180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen last_match_info_elements, 498280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Operand(RegExpImpl::kFirstCaptureOffset - kHeapObjectTag)); 498380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&next_capture); 498480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(r1, r1, Operand(1), SetCC); 498580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(mi, &done); 498680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Read the value from the static offsets vector buffer. 498780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, MemOperand(r2, kPointerSize, PostIndex)); 498880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store the smi value in the last match info. 498980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r3, Operand(r3, LSL, kSmiTagSize)); 499080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r3, MemOperand(r0, kPointerSize, PostIndex)); 499180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&next_capture); 499280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 499380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 499480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return last match info. 499580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, MemOperand(sp, kLastMatchInfoOffset)); 499680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(sp, sp, Operand(4 * kPointerSize)); 499780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 499880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 49993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // External string. Short external strings have already been ruled out. 50003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r0: scratch 50013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&external_string); 50023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); 50033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); 50043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (FLAG_debug_code) { 50053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Assert that we do not have a cons or slice (indirect strings) here. 50063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Sequential strings have already been ruled out. 50073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ tst(r0, Operand(kIsIndirectStringMask)); 50083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Assert(eq, "external string expected, but not found"); 50093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 50103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(subject, 50113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FieldMemOperand(subject, ExternalString::kResourceDataOffset)); 50123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Move the pointer so that offset-wise, it looks like a sequential string. 50133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); 50143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(subject, 50153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch subject, 50163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 50173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&seq_string); 50183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 501980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Do the runtime call to execute the regexp. 502080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 502180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 502280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif // V8_INTERPRETED_REGEXP 502380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 502480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 502580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5026b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid RegExpConstructResultStub::Generate(MacroAssembler* masm) { 5027b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch const int kMaxInlineLength = 100; 5028b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label slowcase; 5029b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label done; 5030257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Factory* factory = masm->isolate()->factory(); 5031257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5032b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ldr(r1, MemOperand(sp, kPointerSize * 2)); 5033b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 5034b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch STATIC_ASSERT(kSmiTagSize == 1); 50353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(r1, &slowcase); 5036b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ cmp(r1, Operand(Smi::FromInt(kMaxInlineLength))); 5037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ b(hi, &slowcase); 5038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Smi-tagging is equivalent to multiplying by 2. 5039b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Allocate RegExpResult followed by FixedArray with size in ebx. 5040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // JSArray: [Map][empty properties][Elements][Length-smi][index][input] 5041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Elements: [Map][Length][..elements..] 5042b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Size of JSArray with two in-object properties and the header of a 5043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // FixedArray. 5044b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch int objects_size = 5045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch (JSRegExpResult::kSize + FixedArray::kHeaderSize) / kPointerSize; 5046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(r5, Operand(r1, LSR, kSmiTagSize + kSmiShiftSize)); 5047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(r2, r5, Operand(objects_size)); 5048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ AllocateInNewSpace( 5049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch r2, // In: Size, in words. 5050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch r0, // Out: Start of allocation (tagged). 5051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch r3, // Scratch register. 5052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch r4, // Scratch register. 5053b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch &slowcase, 5054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS)); 5055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // r0: Start of allocated area, object-tagged. 5056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // r1: Number of elements in array, as smi. 5057b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // r5: Number of elements, untagged. 5058b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set JSArray map to global.regexp_result_map(). 5060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set empty properties FixedArray. 5061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set elements to point to FixedArray allocated right after the JSArray. 5062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Interleave operations for better latency. 5063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ldr(r2, ContextOperand(cp, Context::GLOBAL_INDEX)); 5064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(r3, r0, Operand(JSRegExpResult::kSize)); 5065257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r4, Operand(factory->empty_fixed_array())); 5066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalContextOffset)); 5067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ str(r3, FieldMemOperand(r0, JSObject::kElementsOffset)); 5068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ldr(r2, ContextOperand(r2, Context::REGEXP_RESULT_MAP_INDEX)); 5069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ str(r4, FieldMemOperand(r0, JSObject::kPropertiesOffset)); 5070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); 5071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set input, index and length fields from arguments. 5073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ldr(r1, MemOperand(sp, kPointerSize * 0)); 50743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r2, MemOperand(sp, kPointerSize * 1)); 50753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r6, MemOperand(sp, kPointerSize * 2)); 5076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ str(r1, FieldMemOperand(r0, JSRegExpResult::kInputOffset)); 50773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r2, FieldMemOperand(r0, JSRegExpResult::kIndexOffset)); 50783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r6, FieldMemOperand(r0, JSArray::kLengthOffset)); 5079b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5080b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill out the elements FixedArray. 5081b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // r0: JSArray, tagged. 5082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // r3: FixedArray, tagged. 5083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // r5: Number of elements in array, untagged. 5084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set map. 5086257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r2, Operand(factory->fixed_array_map())); 5087b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ str(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); 5088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Set FixedArray length. 5089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(r6, Operand(r5, LSL, kSmiTagSize)); 5090b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ str(r6, FieldMemOperand(r3, FixedArray::kLengthOffset)); 5091b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill contents of fixed-array with the-hole. 5092257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r2, Operand(factory->the_hole_value())); 5093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(r3, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 5094b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Fill fixed array elements with hole. 5095b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // r0: JSArray, tagged. 5096b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // r2: the hole. 5097b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // r3: Start of elements in FixedArray. 5098b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // r5: Number of elements to fill. 5099b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label loop; 51003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(r5, Operand(0)); 5101b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&loop); 51023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(le, &done); // Jump if r5 is negative or zero. 5103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(r5, r5, Operand(1), SetCC); 5104b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ str(r2, MemOperand(r3, r5, LSL, kPointerSizeLog2)); 5105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ jmp(&loop); 5106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&done); 5108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ add(sp, sp, Operand(3 * kPointerSize)); 5109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 5110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&slowcase); 5112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); 5113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 5114b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 5115b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 51163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic void GenerateRecordCallTarget(MacroAssembler* masm) { 51173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Cache the called function in a global property cell. Cache states 51183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // are uninitialized, monomorphic (indicated by a JSFunction), and 51193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // megamorphic. 51203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r1 : the function to call 51213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r2 : cache cell for call target 51223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label done; 51233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 51243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()), 51253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm->isolate()->heap()->undefined_value()); 51263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()), 51273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm->isolate()->heap()->the_hole_value()); 51283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 51293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load the cache state into r3. 51303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset)); 51313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 51323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // A monomorphic cache hit or an already megamorphic state: invoke the 51333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // function without changing the state. 51343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(r3, r1); 51353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &done); 51363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(r3, Heap::kUndefinedValueRootIndex); 51373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &done); 51383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 51393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // A monomorphic miss (i.e, here the cache is not uninitialized) goes 51403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // megamorphic. 51413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); 51423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // MegamorphicSentinel is an immortal immovable object (undefined) so no 51433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // write-barrier is needed. 51443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ LoadRoot(ip, Heap::kUndefinedValueRootIndex, ne); 51453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(ip, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset), ne); 51463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 51473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // An uninitialized cache is patched with the function. 51483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r1, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset), eq); 51493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // No need for a write barrier here - cells are rescanned. 51503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 51513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&done); 51523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 51533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 51543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 515580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CallFunctionStub::Generate(MacroAssembler* masm) { 51563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r1 : the function to call 51573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r2 : cache cell for call target 5158589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Label slow, non_function; 515980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5160257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // The receiver might implicitly be the global object. This is 5161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // indicated by passing the hole as the receiver to the call 5162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // function stub. 5163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (ReceiverMightBeImplicit()) { 5164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label call; 516580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the receiver from the stack. 516680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // function, receiver [, arguments] 5167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(r4, MemOperand(sp, argc_ * kPointerSize)); 5168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Call as function is indicated with the hole. 5169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CompareRoot(r4, Heap::kTheHoleValueRootIndex); 5170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(ne, &call); 5171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Patch the receiver on the stack with the global receiver object. 51723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); 51733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); 51743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r2, MemOperand(sp, argc_ * kPointerSize)); 5175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call); 517680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 517780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 517880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the function is really a JavaScript function. 517980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1: pushed function (to be verified) 5180589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ JumpIfSmi(r1, &non_function); 518180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the map of the function object. 518280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); 518380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &slow); 518480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 518580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fast-case: Invoke the function now. 518680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1: pushed function 518780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ParameterCount actual(argc_); 5188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 5189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (ReceiverMightBeImplicit()) { 5190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label call_as_function; 5191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CompareRoot(r4, Heap::kTheHoleValueRootIndex); 5192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(eq, &call_as_function); 5193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeFunction(r1, 5194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch actual, 5195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch JUMP_FUNCTION, 5196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch NullCallWrapper(), 5197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CALL_AS_METHOD); 5198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&call_as_function); 5199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 5200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeFunction(r1, 5201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch actual, 5202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch JUMP_FUNCTION, 5203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch NullCallWrapper(), 5204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch CALL_AS_FUNCTION); 520580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 520680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Slow-case: Non-function called. 520780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow); 5208589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // Check for function proxy. 5209589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ cmp(r2, Operand(JS_FUNCTION_PROXY_TYPE)); 5210589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ b(ne, &non_function); 5211589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ push(r1); // put proxy as additional argument 5212589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ mov(r0, Operand(argc_ + 1, RelocInfo::NONE)); 5213589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ mov(r2, Operand(0, RelocInfo::NONE)); 5214589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY); 52153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ SetCallKind(r5, CALL_AS_METHOD); 5216589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch { 5217589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Handle<Code> adaptor = 5218589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); 5219589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ Jump(adaptor, RelocInfo::CODE_TARGET); 5220589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch } 5221589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 522280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // CALL_NON_FUNCTION expects the non-function callee as receiver (instead 522380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // of the original receiver from the call site). 5224589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ bind(&non_function); 522580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r1, MemOperand(sp, argc_ * kPointerSize)); 52263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r0, Operand(argc_)); // Set up the number of arguments. 52279ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ mov(r2, Operand(0, RelocInfo::NONE)); 522880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); 52293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ SetCallKind(r5, CALL_AS_METHOD); 523044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), 523180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen RelocInfo::CODE_TARGET); 523280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 523380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 523480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 52353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CallConstructStub::Generate(MacroAssembler* masm) { 52363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r0 : number of arguments 52373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r1 : the function to call 52383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r2 : cache cell for call target 52393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label slow, non_function_call; 52403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 52413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Check that the function is not a smi. 52423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfSmi(r1, &non_function_call); 52433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Check that the function is a JSFunction. 52443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE); 52453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &slow); 52463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 52473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (RecordCallTarget()) { 52483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateRecordCallTarget(masm); 52493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 52503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 52513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Jump to the function-specific construct stub. 52523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); 52533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kConstructStubOffset)); 52543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(pc, r2, Operand(Code::kHeaderSize - kHeapObjectTag)); 52553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 52563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r0: number of arguments 52573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r1: called object 52583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r3: object type 52593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label do_call; 52603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&slow); 52613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(r3, Operand(JS_FUNCTION_PROXY_TYPE)); 52623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &non_function_call); 52633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR); 52643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&do_call); 52653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 52663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&non_function_call); 52673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); 52683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&do_call); 52693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Set expected number of arguments to zero (not changing r0). 52703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r2, Operand(0, RelocInfo::NONE)); 52713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ SetCallKind(r5, CALL_AS_METHOD); 52723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), 52733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch RelocInfo::CODE_TARGET); 52743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 52753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 52763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 52773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Unfortunately you have to run without snapshots to see most of these 52783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// names in the profile since most compare stubs end up in the snapshot. 52793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CompareStub::PrintName(StringStream* stream) { 528080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT((lhs_.is(r0) && rhs_.is(r1)) || 528180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen (lhs_.is(r1) && rhs_.is(r0))); 528280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const char* cc_name; 528380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen switch (cc_) { 528480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case lt: cc_name = "LT"; break; 528580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case gt: cc_name = "GT"; break; 528680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case le: cc_name = "LE"; break; 528780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case ge: cc_name = "GE"; break; 528880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case eq: cc_name = "EQ"; break; 528980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen case ne: cc_name = "NE"; break; 529080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen default: cc_name = "UnknownCondition"; break; 529180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 52923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch bool is_equality = cc_ == eq || cc_ == ne; 52933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add("CompareStub_%s", cc_name); 52943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add(lhs_.is(r0) ? "_r0" : "_r1"); 52953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch stream->Add(rhs_.is(r0) ? "_r0" : "_r1"); 52963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (strict_ && is_equality) stream->Add("_STRICT"); 52973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN"); 52983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (!include_number_compare_) stream->Add("_NO_NUMBER"); 52993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (!include_smi_compare_) stream->Add("_NO_SMI"); 530080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 530180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 530280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 530380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenint CompareStub::MinorKey() { 530480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Encode the three parameters in a unique 16 bit value. To avoid duplicate 530580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // stubs the never NaN NaN condition is only taken into account if the 530680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // condition is equals. 530780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT((static_cast<unsigned>(cc_) >> 28) < (1 << 12)); 530880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT((lhs_.is(r0) && rhs_.is(r1)) || 530980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen (lhs_.is(r1) && rhs_.is(r0))); 531080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return ConditionField::encode(static_cast<unsigned>(cc_) >> 28) 531180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | RegisterField::encode(lhs_.is(r0)) 531280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | StrictField::encode(strict_) 531380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false) 53140d5e116f6aee03185f237311a943491bb079a768Kristian Monsen | IncludeNumberCompareField::encode(include_number_compare_) 53150d5e116f6aee03185f237311a943491bb079a768Kristian Monsen | IncludeSmiCompareField::encode(include_smi_compare_); 531680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 531780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 531880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 531980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharCodeAtGenerator 532080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { 532180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label flat_string; 532280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label ascii_string; 532380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label got_char_code; 532469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label sliced_string; 532580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 532680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the receiver is a smi trigger the non-string case. 53271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfSmi(object_, receiver_not_string_); 532880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 532980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fetch the instance type of the receiver into result register. 533080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); 533180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); 533280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the receiver is not a string trigger the non-string case. 533380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(result_, Operand(kIsNotStringMask)); 533480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, receiver_not_string_); 533580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 533680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If the index is non-smi trigger the non-smi case. 53371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfNotSmi(index_, &index_not_smi_); 533880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&got_smi_index_); 533980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 534080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check for index out of range. 534180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(ip, FieldMemOperand(object_, String::kLengthOffset)); 53423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(ip, Operand(index_)); 534380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ls, index_out_of_range_); 534480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 53453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(index_, Operand(index_, ASR, kSmiTagSize)); 5346592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch 53473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch StringCharLoadGenerator::Generate(masm, 53483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch object_, 53493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch index_, 53503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch result_, 53513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &call_runtime_); 535280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 535380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(result_, Operand(result_, LSL, kSmiTagSize)); 535480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&exit_); 535580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 535680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 535780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 535880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateSlow( 53593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler* masm, 53603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const RuntimeCallHelper& call_helper) { 536180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough to CharCodeAt slow case"); 536280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 536380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Index is not a smi. 536480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&index_not_smi_); 536580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If index is a heap number, try converting it to an integer. 536680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CheckMap(index_, 53673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch result_, 536880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Heap::kHeapNumberMapRootIndex, 536980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index_not_number_, 5370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch DONT_DO_SMI_CHECK); 537180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 53723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(object_); 537380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(index_); // Consumed by runtime conversion function. 537480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (index_flags_ == STRING_INDEX_IS_NUMBER) { 537580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); 537680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 537780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); 537880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // NumberToSmi discards numbers that are not exact integers. 537980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kNumberToSmi, 1); 538080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 538180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Save the conversion result before the pop instructions below 538280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // have a chance to overwrite it. 53833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Move(index_, r0); 538480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ pop(object_); 538580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Reload the instance type. 538680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); 538780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); 538880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 538980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If index is still not a smi, it must be out of range. 53903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfNotSmi(index_, index_out_of_range_); 539180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Otherwise, return to the fast path. 539280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&got_smi_index_); 539380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 539480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call runtime. We get here when the receiver is a string and the 539580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // index is a number, but the code of getting the actual character 539680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // is too complex (e.g., when the string needs to be flattened). 539780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&call_runtime_); 539880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 53993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(index_, Operand(index_, LSL, kSmiTagSize)); 540080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Push(object_, index_); 540180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kStringCharCodeAt, 2); 540280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Move(result_, r0); 540380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 540480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&exit_); 540580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 540680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough from CharCodeAt slow case"); 540780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 540880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 540980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 541080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// ------------------------------------------------------------------------- 541180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharFromCodeGenerator 541280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 541380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { 541480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fast case of Heap::LookupSingleCharacterStringFromCode. 541580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 541680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiShiftSize == 0); 541780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); 541880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(code_, 541980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Operand(kSmiTagMask | 542080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ((~String::kMaxAsciiCharCode) << kSmiTagSize))); 54211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ b(ne, &slow_case_); 542280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 542380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); 542444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // At this point code register contains smi tagged ASCII char code. 542580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 542680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(result_, result_, Operand(code_, LSL, kPointerSizeLog2 - kSmiTagSize)); 542780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize)); 54283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(result_, Heap::kUndefinedValueRootIndex); 542980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &slow_case_); 543080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&exit_); 543180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 543280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 543380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 543480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateSlow( 54353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler* masm, 54363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const RuntimeCallHelper& call_helper) { 543780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough to CharFromCode slow case"); 543880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 543980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&slow_case_); 544080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.BeforeCall(masm); 544180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ push(code_); 544280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ CallRuntime(Runtime::kCharFromCode, 1); 544380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Move(result_, r0); 544480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen call_helper.AfterCall(masm); 544580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&exit_); 544680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 544780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Abort("Unexpected fallthrough from CharFromCode slow case"); 544880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 544980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 545080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 545180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// ------------------------------------------------------------------------- 545280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharAtGenerator 545380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 545480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateFast(MacroAssembler* masm) { 545580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_code_at_generator_.GenerateFast(masm); 545680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_from_code_generator_.GenerateFast(masm); 545780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 545880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 545980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 546080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateSlow( 54613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler* masm, 54623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const RuntimeCallHelper& call_helper) { 546380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_code_at_generator_.GenerateSlow(masm, call_helper); 546480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_from_code_generator_.GenerateSlow(masm, call_helper); 546580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 546680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 546780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 546880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharacters(MacroAssembler* masm, 546980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register dest, 547080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register src, 547180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register count, 547280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch, 547380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool ascii) { 547480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label loop; 547580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label done; 547680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // This loop just copies one character at a time, as it is only used for very 547780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // short strings. 547880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!ascii) { 547980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(count, count, Operand(count), SetCC); 548080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 54819ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ cmp(count, Operand(0, RelocInfo::NONE)); 548280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 548380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &done); 548480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 548580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 548680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(scratch, MemOperand(src, 1, PostIndex)); 548780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Perform sub between load and dependent store to get the load time to 548880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // complete. 548980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(count, count, Operand(1), SetCC); 549080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ strb(scratch, MemOperand(dest, 1, PostIndex)); 549180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // last iteration. 549280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(gt, &loop); 549380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 549480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 549580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 549680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 549780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 549880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenenum CopyCharactersFlags { 549980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen COPY_ASCII = 1, 550080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen DEST_ALWAYS_ALIGNED = 2 550180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}; 550280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 550380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 550480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm, 550580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register dest, 550680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register src, 550780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register count, 550880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 550980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 551080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch3, 551180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch4, 551280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch5, 551380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen int flags) { 551480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool ascii = (flags & COPY_ASCII) != 0; 551580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen bool dest_always_aligned = (flags & DEST_ALWAYS_ALIGNED) != 0; 551680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 551780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (dest_always_aligned && FLAG_debug_code) { 551880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that destination is actually word aligned if the flag says 551980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // that it is. 552080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(dest, Operand(kPointerAlignmentMask)); 552180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Check(eq, "Destination of copy not aligned."); 552280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 552380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 552480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const int kReadAlignment = 4; 552580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const int kReadAlignmentMask = kReadAlignment - 1; 552680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Ensure that reading an entire aligned word containing the last character 552780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // of a string will not read outside the allocated area (because we pad up 552880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // to kObjectAlignment). 552980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kObjectAlignment >= kReadAlignment); 553080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Assumes word reads and writes are little endian. 553180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Nothing to do for zero characters. 553280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label done; 553380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!ascii) { 553480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(count, count, Operand(count), SetCC); 553580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 55369ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick __ cmp(count, Operand(0, RelocInfo::NONE)); 553780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 553880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &done); 553980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 554080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Assume that you cannot read (or write) unaligned. 554180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label byte_loop; 554280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Must copy at least eight bytes, otherwise just do it one byte at a time. 554380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(count, Operand(8)); 554480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(count, dest, Operand(count)); 554580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register limit = count; // Read until src equals this. 554680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(lt, &byte_loop); 554780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 554880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (!dest_always_aligned) { 554980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Align dest by byte copying. Copies between zero and three bytes. 555080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(scratch4, dest, Operand(kReadAlignmentMask), SetCC); 555180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label dest_aligned; 555280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &dest_aligned); 555380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(scratch4, Operand(2)); 555480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(scratch1, MemOperand(src, 1, PostIndex)); 555580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(scratch2, MemOperand(src, 1, PostIndex), le); 555680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(scratch3, MemOperand(src, 1, PostIndex), lt); 555780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ strb(scratch1, MemOperand(dest, 1, PostIndex)); 555880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ strb(scratch2, MemOperand(dest, 1, PostIndex), le); 555980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ strb(scratch3, MemOperand(dest, 1, PostIndex), lt); 556080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&dest_aligned); 556180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 556280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 556380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label simple_loop; 556480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 556580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(scratch4, dest, Operand(src)); 556680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(scratch4, scratch4, Operand(0x03), SetCC); 556780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &simple_loop); 556880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Shift register is number of bits in a source word that 556980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // must be combined with bits in the next source word in order 557080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // to create a destination word. 557180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 557280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Complex loop for src/dst that are not aligned the same way. 557380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen { 557480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label loop; 557580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch4, Operand(scratch4, LSL, 3)); 557680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register left_shift = scratch4; 557780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(src, src, Operand(~3)); // Round down to load previous word. 557880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(scratch1, MemOperand(src, 4, PostIndex)); 557980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Store the "shift" most significant bits of scratch in the least 558080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // signficant bits (i.e., shift down by (32-shift)). 558180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ rsb(scratch2, left_shift, Operand(32)); 558280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register right_shift = scratch2; 558380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch1, Operand(scratch1, LSR, right_shift)); 558480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 558580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 558680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(scratch3, MemOperand(src, 4, PostIndex)); 558780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(scratch5, limit, Operand(dest)); 558880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ orr(scratch1, scratch1, Operand(scratch3, LSL, left_shift)); 558980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(scratch1, MemOperand(dest, 4, PostIndex)); 559080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch1, Operand(scratch3, LSR, right_shift)); 559180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Loop if four or more bytes left to copy. 559280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compare to eight, because we did the subtract before increasing dst. 559380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(scratch5, scratch5, Operand(8), SetCC); 559480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ge, &loop); 559580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 559680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // There is now between zero and three bytes left to copy (negative that 559780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // number is in scratch5), and between one and three bytes already read into 559880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // scratch1 (eight times that number in scratch4). We may have read past 559980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the end of the string, but because objects are aligned, we have not read 560080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // past the end of the object. 560180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find the minimum of remaining characters to move and preloaded characters 560280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // and write those as bytes. 560380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(scratch5, scratch5, Operand(4), SetCC); 560480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &done); 560580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(scratch4, Operand(scratch5, LSL, 3), ne); 560680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Move minimum of bytes read and bytes left to copy to scratch4. 560780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch5, Operand(scratch4, LSR, 3), LeaveCC, lt); 560880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Between one and three (value in scratch5) characters already read into 560980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // scratch ready to write. 561080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(scratch5, Operand(2)); 561180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ strb(scratch1, MemOperand(dest, 1, PostIndex)); 561280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch1, Operand(scratch1, LSR, 8), LeaveCC, ge); 561380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ strb(scratch1, MemOperand(dest, 1, PostIndex), ge); 561480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch1, Operand(scratch1, LSR, 8), LeaveCC, gt); 561580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ strb(scratch1, MemOperand(dest, 1, PostIndex), gt); 561680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy any remaining bytes. 561780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(&byte_loop); 561880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 561980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Simple loop. 562080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy words from src to dst, until less than four bytes left. 562180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both src and dest are word aligned. 562280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&simple_loop); 562380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen { 562480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label loop; 562580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&loop); 562680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(scratch1, MemOperand(src, 4, PostIndex)); 562780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(scratch3, limit, Operand(dest)); 562880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(scratch1, MemOperand(dest, 4, PostIndex)); 562980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Compare to 8, not 4, because we do the substraction before increasing 563080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // dest. 563180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(scratch3, Operand(8)); 563280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ge, &loop); 563380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 563480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 563580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Copy bytes from src to dst until dst hits limit. 563680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&byte_loop); 563780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(dest, Operand(limit)); 563880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt); 563980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ge, &done); 564080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ strb(scratch1, MemOperand(dest, 1, PostIndex)); 564180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(&byte_loop); 564280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 564380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&done); 564480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 564580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 564680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 564780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, 564880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register c1, 564980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register c2, 565080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 565180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 565280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch3, 565380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch4, 565480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch5, 565580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label* not_found) { 565680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Register scratch3 is the general scratch register in this function. 565780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch = scratch3; 565880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 565980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure that both characters are not digits as such strings has a 566080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // different hash algorithm. Don't try to look for these in the symbol table. 566180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label not_array_index; 566280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(scratch, c1, Operand(static_cast<int>('0'))); 566380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(scratch, Operand(static_cast<int>('9' - '0'))); 566480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(hi, ¬_array_index); 566580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(scratch, c2, Operand(static_cast<int>('0'))); 566680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(scratch, Operand(static_cast<int>('9' - '0'))); 566780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 566880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If check failed combine both characters into single halfword. 566980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // This is required by the contract of the method: code at the 567080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // not_found branch expects this combination in c1 register 567180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ orr(c1, c1, Operand(c2, LSL, kBitsPerByte), LeaveCC, ls); 567280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ls, not_found); 567380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 567480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_array_index); 567580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate the two character string hash. 567680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash = scratch1; 567780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateHashInit(masm, hash, c1); 567880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateHashAddCharacter(masm, hash, c2); 567980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateHashGetHash(masm, hash); 568080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 568180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Collect the two characters in a register. 568280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register chars = c1; 568380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ orr(chars, chars, Operand(c2, LSL, kBitsPerByte)); 568480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 568580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 568680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash: hash of two character string. 568780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 568880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load symbol table 568980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load address of first element of the symbol table. 569080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register symbol_table = c2; 569180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex); 569280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 569380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register undefined = scratch4; 569480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex); 569580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 569680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate capacity mask from the symbol table capacity. 569780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register mask = scratch2; 569880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(mask, FieldMemOperand(symbol_table, SymbolTable::kCapacityOffset)); 569980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(mask, Operand(mask, ASR, 1)); 570080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(mask, mask, Operand(1)); 570180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 570280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate untagged address of the first element of the symbol table. 570380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register first_symbol_table_element = symbol_table; 570480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(first_symbol_table_element, symbol_table, 570580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Operand(SymbolTable::kElementsStartOffset - kHeapObjectTag)); 570680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 570780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Registers 570880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 570980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash: hash of two character string 571080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // mask: capacity mask 571180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // first_symbol_table_element: address of the first element of 571280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // the symbol table 571344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // undefined: the undefined object 571480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // scratch: - 571580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 571680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Perform a number of probes in the symbol table. 57173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kProbes = 4; 571880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label found_in_symbol_table; 571980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label next_probe[kProbes]; 5720692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch Register candidate = scratch5; // Scratch register contains candidate. 572180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen for (int i = 0; i < kProbes; i++) { 572280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Calculate entry in symbol table. 572380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (i > 0) { 572480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(candidate, hash, Operand(SymbolTable::GetProbeOffset(i))); 572580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 572680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(candidate, hash); 572780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 572880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 572980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(candidate, candidate, Operand(mask)); 573080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 573180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the entry from the symble table. 573280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(SymbolTable::kEntrySize == 1); 573380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(candidate, 573480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen MemOperand(first_symbol_table_element, 573580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen candidate, 573680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen LSL, 573780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen kPointerSizeLog2)); 573880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 573980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If entry is undefined no string with this hash can be found. 574044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Label is_string; 574144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CompareObjectType(candidate, scratch, scratch, ODDBALL_TYPE); 574244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ b(ne, &is_string); 574344f0eee88ff00398ff7f715fab053374d808c90dSteve Block 574444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(undefined, candidate); 574580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, not_found); 57463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Must be the hole (deleted entry). 574744f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (FLAG_debug_code) { 57483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); 574944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmp(ip, candidate); 57503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Assert(eq, "oddball in symbol table is not undefined or the hole"); 575144f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 575244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ jmp(&next_probe[i]); 575344f0eee88ff00398ff7f715fab053374d808c90dSteve Block 575444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&is_string); 575544f0eee88ff00398ff7f715fab053374d808c90dSteve Block 575644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Check that the candidate is a non-external ASCII string. The instance 575744f0eee88ff00398ff7f715fab053374d808c90dSteve Block // type is still in the scratch register from the CompareObjectType 575844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // operation. 575944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &next_probe[i]); 576080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 576180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If length is not 2 the string is not a candidate. 576280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(scratch, FieldMemOperand(candidate, String::kLengthOffset)); 576380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(scratch, Operand(Smi::FromInt(2))); 576480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &next_probe[i]); 576580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 576680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if the two characters match. 576780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Assumes that word load is little endian. 576880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrh(scratch, FieldMemOperand(candidate, SeqAsciiString::kHeaderSize)); 576980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(chars, scratch); 577080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &found_in_symbol_table); 577180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&next_probe[i]); 577280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 577380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 577480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // No matching 2 character string found by probing. 577580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(not_found); 577680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 577780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Scratch register contains result when we fall through to here. 5778692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch Register result = candidate; 577980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&found_in_symbol_table); 578080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Move(r0, result); 578180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 578280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 578380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 578480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashInit(MacroAssembler* masm, 578580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 578680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register character) { 578780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash = character + (character << 10); 5788c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ LoadRoot(hash, Heap::kHashSeedRootIndex); 5789c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch // Untag smi seed and add the character. 5790c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ add(hash, character, Operand(hash, LSR, kSmiTagSize)); 5791c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch // hash += hash << 10; 5792c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ add(hash, hash, Operand(hash, LSL, 10)); 579380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 6; 5794692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ eor(hash, hash, Operand(hash, LSR, 6)); 579580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 579680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 579780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 579880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, 579980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash, 580080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register character) { 580180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += character; 580280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(hash, hash, Operand(character)); 580380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 10; 580480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(hash, hash, Operand(hash, LSL, 10)); 580580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 6; 5806692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ eor(hash, hash, Operand(hash, LSR, 6)); 580780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 580880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 580980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 581080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashGetHash(MacroAssembler* masm, 581180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register hash) { 581280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 3; 581380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(hash, hash, Operand(hash, LSL, 3)); 581480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash ^= hash >> 11; 5815692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch __ eor(hash, hash, Operand(hash, LSR, 11)); 581680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // hash += hash << 15; 5817c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ add(hash, hash, Operand(hash, LSL, 15)); 5818692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch 5819c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ and_(hash, hash, Operand(String::kHashBitMask), SetCC); 582080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 582180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // if (hash == 0) hash = 27; 5822c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch __ mov(hash, Operand(StringHasher::kZeroHash), LeaveCC, eq); 582380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 582480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 582580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 582680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid SubStringStub::Generate(MacroAssembler* masm) { 582780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 582880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 582980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 583080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // lr: return address 583180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // sp[0]: to 583280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // sp[4]: from 583380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // sp[8]: string 583480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 583580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // This stub is called from the native-call %_SubString(...), so 583680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // nothing can be assumed about the arguments. It is tested that: 583780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // "string" is a sequential string, 583880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // both "from" and "to" are smis, and 583980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // 0 <= from <= to <= string.length. 584080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If any of these assumptions fail, we call the runtime system. 584180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 58423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kToOffset = 0 * kPointerSize; 58433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kFromOffset = 1 * kPointerSize; 58443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kStringOffset = 2 * kPointerSize; 584580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 58463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ldrd(r2, r3, MemOperand(sp, kToOffset)); 58470d5e116f6aee03185f237311a943491bb079a768Kristian Monsen STATIC_ASSERT(kFromOffset == kToOffset + 4); 584880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 584980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 585069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 585180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // I.e., arithmetic shift right by one un-smi-tags. 58523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r2, Operand(r2, ASR, 1), SetCC); 58533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r3, Operand(r3, ASR, 1), SetCC, cc); 58540d5e116f6aee03185f237311a943491bb079a768Kristian Monsen // If either to or from had the smi tag bit set, then carry is set now. 585580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(cs, &runtime); // Either "from" or "to" is not a smi. 58563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // We want to bailout to runtime here if From is negative. In that case, the 58573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // next instruction is not executed and we fall through to bailing out to 58583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // runtime. pl is the opposite of mi. 58593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Both r2 and r3 are untagged integers. 58603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(r2, r2, Operand(r3), SetCC, pl); 586180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(mi, &runtime); // Fail if from > to. 586280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 58633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Make sure first argument is a string. 5864589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ ldr(r0, MemOperand(sp, kStringOffset)); 586580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 5866589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ JumpIfSmi(r0, &runtime); 5867589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Condition is_string = masm->IsObjectStringType(r0, r1); 586880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(NegateCondition(is_string), &runtime); 586980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 5870589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // Short-cut for the case of trivial substring. 5871589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Label return_r0; 5872589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // r0: original string 5873589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // r2: result string length 5874589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ ldr(r4, FieldMemOperand(r0, String::kLengthOffset)); 5875589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ cmp(r2, Operand(r4, ASR, 1)); 5876589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ b(eq, &return_r0); 5877589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 587880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label result_longer_than_two; 58793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Check for special case of two character ASCII string, in which case 58803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // we do a lookup in the symbol table first. 588180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r2, Operand(2)); 588280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(gt, &result_longer_than_two); 58833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(lt, &runtime); 58843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 58853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfInstanceTypeIsNotSequentialAscii(r1, r1, &runtime); 588680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 588780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the two characters forming the sub string. 5888589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ add(r0, r0, Operand(r3)); 5889589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ ldrb(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); 5890589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ ldrb(r4, FieldMemOperand(r0, SeqAsciiString::kHeaderSize + 1)); 589180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 589280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try to lookup two character string in symbol table. 589380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label make_two_character_string; 589480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateTwoCharacterSymbolTableProbe( 589580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string); 5896589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ jmp(&return_r0); 589780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 589880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: result string length. 589980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r3: two characters combined into halfword in little endian byte order. 590080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&make_two_character_string); 590180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime); 590280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); 5903589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ jmp(&return_r0); 590480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 590580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&result_longer_than_two); 59063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Deal with different string types: update the index if necessary 59073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // and put the underlying string into r5. 59083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r0: original string 59093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r1: instance type 59103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r2: length 59113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r3: from index (untagged) 59123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label underlying_unpacked, sliced_string, seq_or_external_string; 59133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // If the string is not indirect, it can only be sequential or external. 59143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); 59153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kIsIndirectStringMask != 0); 59163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ tst(r1, Operand(kIsIndirectStringMask)); 59173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &seq_or_external_string); 59183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 59193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ tst(r1, Operand(kSlicedNotConsMask)); 59203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &sliced_string); 59213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Cons string. Check whether it is flat, then fetch first part. 59223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r5, FieldMemOperand(r0, ConsString::kSecondOffset)); 59233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(r5, Heap::kEmptyStringRootIndex); 59243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &runtime); 59253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r5, FieldMemOperand(r0, ConsString::kFirstOffset)); 59263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Update instance type. 59273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r1, FieldMemOperand(r5, HeapObject::kMapOffset)); 59283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); 59293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&underlying_unpacked); 5930c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch 59313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&sliced_string); 59323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Sliced string. Fetch parent and correct start index by offset. 59333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r5, FieldMemOperand(r0, SlicedString::kParentOffset)); 59343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r4, FieldMemOperand(r0, SlicedString::kOffsetOffset)); 59353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r3, r3, Operand(r4, ASR, 1)); // Add offset to index. 59363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Update instance type. 59373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r1, FieldMemOperand(r5, HeapObject::kMapOffset)); 59383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); 59393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&underlying_unpacked); 5940c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch 59413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&seq_or_external_string); 59423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Sequential or external string. Just move string to the expected register. 59433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r5, r0); 5944c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch 59453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&underlying_unpacked); 59463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 59473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (FLAG_string_slices) { 59483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label copy_routine; 59493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r5: underlying subject string 59503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r1: instance type of underlying subject string 59513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r2: length 59523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r3: adjusted start index (untagged) 59533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(r2, Operand(SlicedString::kMinLength)); 59543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Short slice. Copy instead of slicing. 59553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(lt, ©_routine); 59563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Allocate new sliced string. At this point we do not reload the instance 59573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // type including the string encoding because we simply rely on the info 59583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // provided by the original string. It does not matter if the original 59593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // string's encoding is wrong because we always have to recheck encoding of 59603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // the newly created string's parent anyways due to externalized strings. 59613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label two_byte_slice, set_slice_header; 59623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 59633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 59643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ tst(r1, Operand(kStringEncodingMask)); 59653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &two_byte_slice); 59663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateAsciiSlicedString(r0, r2, r6, r7, &runtime); 59673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&set_slice_header); 59683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&two_byte_slice); 59693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateTwoByteSlicedString(r0, r2, r6, r7, &runtime); 59703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&set_slice_header); 59713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r3, Operand(r3, LSL, 1)); 59723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r5, FieldMemOperand(r0, SlicedString::kParentOffset)); 59733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r3, FieldMemOperand(r0, SlicedString::kOffsetOffset)); 59743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&return_r0); 59753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 59763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(©_routine); 59773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 59783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 59793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r5: underlying subject string 59803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r1: instance type of underlying subject string 59813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r2: length 59823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r3: adjusted start index (untagged) 59833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label two_byte_sequential, sequential_string, allocate_result; 59843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kExternalStringTag != 0); 59853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kSeqStringTag == 0); 59863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ tst(r1, Operand(kExternalStringTag)); 59873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &sequential_string); 59883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 59893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Handle external string. 59903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Rule out short external strings. 59913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_CHECK(kShortExternalStringTag != 0); 59923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ tst(r1, Operand(kShortExternalStringTag)); 59933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &runtime); 59943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r5, FieldMemOperand(r5, ExternalString::kResourceDataOffset)); 59953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r5 already points to the first character of underlying string. 59963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&allocate_result); 59973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 59983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&sequential_string); 59993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Locate first character of underlying subject string. 60003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); 60013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r5, r5, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 60023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 60033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&allocate_result); 60043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Sequential acii string. Allocate the result. 60053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0); 60063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ tst(r1, Operand(kStringEncodingMask)); 60073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &two_byte_sequential); 60083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 60093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Allocate and copy the resulting ASCII string. 60103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateAsciiString(r0, r2, r4, r6, r7, &runtime); 60113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 60123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Locate first character of substring to copy. 60133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r5, r5, r3); 601480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 601580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 601680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6017589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // r0: result string 6018589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // r1: first character of result string 6019589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // r2: result string length 6020589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // r5: first character of substring to copy 602180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); 602280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, 602380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen COPY_ASCII | DEST_ALWAYS_ALIGNED); 6024589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ jmp(&return_r0); 602580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 60263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Allocate and copy the resulting two-byte string. 60273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&two_byte_sequential); 60283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateTwoByteString(r0, r2, r4, r6, r7, &runtime); 602980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 60303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Locate first character of substring to copy. 6031589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 60323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r5, r5, Operand(r3, LSL, 1)); 603380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Locate first character of result. 603480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 6035589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 603680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0: result string. 603780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1: first character of result. 603880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: result length. 6039589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // r5: first character of substring to copy. 604080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); 60410d5e116f6aee03185f237311a943491bb079a768Kristian Monsen StringHelper::GenerateCopyCharactersLong( 60420d5e116f6aee03185f237311a943491bb079a768Kristian Monsen masm, r1, r5, r2, r3, r4, r6, r7, r9, DEST_ALWAYS_ALIGNED); 6043589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 6044589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch __ bind(&return_r0); 60453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Counters* counters = masm->isolate()->counters(); 604644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); 604780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(sp, sp, Operand(3 * kPointerSize)); 604880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 604980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 605080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump to runtime to create the sub string. 605180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 605280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kSubString, 3, 1); 605380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 605480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 605580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6056257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, 6057257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left, 6058257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right, 6059257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch1, 6060257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch2, 6061257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch3) { 6062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register length = scratch1; 6063257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6064257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare lengths. 6065257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label strings_not_equal, check_zero_length; 6066257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(length, FieldMemOperand(left, String::kLengthOffset)); 6067257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset)); 6068257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(length, scratch2); 6069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(eq, &check_zero_length); 6070257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&strings_not_equal); 6071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, Operand(Smi::FromInt(NOT_EQUAL))); 6072257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Ret(); 6073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6074257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the length is zero. 6075257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label compare_chars; 6076257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&check_zero_length); 6077257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 60783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(length, Operand(0)); 6079257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(ne, &compare_chars); 6080257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, Operand(Smi::FromInt(EQUAL))); 6081257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Ret(); 6082257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6083257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare characters. 6084257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&compare_chars); 6085257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateAsciiCharsCompareLoop(masm, 6086257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch left, right, length, scratch2, scratch3, 6087257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch &strings_not_equal); 6088257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Characters are equal. 6090257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, Operand(Smi::FromInt(EQUAL))); 6091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Ret(); 6092257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6093257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 609580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, 609680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register left, 609780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register right, 609880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1, 609980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2, 610080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch3, 610180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch4) { 6102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label result_not_equal, compare_lengths; 610380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Find minimum length and length difference. 610480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(scratch1, FieldMemOperand(left, String::kLengthOffset)); 610580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset)); 610680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ sub(scratch3, scratch1, Operand(scratch2), SetCC); 610780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register length_delta = scratch3; 610880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(scratch1, scratch2, LeaveCC, gt); 610980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register min_length = scratch1; 611080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 61113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(min_length, Operand(0)); 611280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &compare_lengths); 611380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare loop. 6115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateAsciiCharsCompareLoop(masm, 6116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch left, right, min_length, scratch2, scratch4, 6117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch &result_not_equal); 611880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6119257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare lengths - strings up to min-length are equal. 612080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&compare_lengths); 612180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(Smi::FromInt(EQUAL) == static_cast<Smi*>(0)); 6122257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Use length_delta as result if it's zero. 6123257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, Operand(length_delta), SetCC); 6124257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&result_not_equal); 6125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Conditionally update the result based either on length_delta or 6126257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // the last comparion performed in the loop above. 612780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(Smi::FromInt(GREATER)), LeaveCC, gt); 612880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(Smi::FromInt(LESS)), LeaveCC, lt); 612980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 613080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 613180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 613280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6133257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateAsciiCharsCompareLoop( 6134257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch MacroAssembler* masm, 6135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left, 6136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right, 6137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register length, 6138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch1, 6139257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch2, 6140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* chars_not_equal) { 6141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Change index to run from -length to -1 by adding length to string 6142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // start. This means that loop ends when index reaches zero, which 6143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // doesn't need an additional compare. 6144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ SmiUntag(length); 6145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(scratch1, length, 6146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 6147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(left, left, Operand(scratch1)); 6148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(right, right, Operand(scratch1)); 614969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ rsb(length, length, Operand::Zero()); 6150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register index = length; // index = -length; 6151257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare loop. 6153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label loop; 6154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&loop); 6155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldrb(scratch1, MemOperand(left, index)); 6156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldrb(scratch2, MemOperand(right, index)); 6157257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(scratch1, scratch2); 6158257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(ne, chars_not_equal); 6159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(index, index, Operand(1), SetCC); 6160257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(ne, &loop); 6161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 616480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::Generate(MacroAssembler* masm) { 616580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label runtime; 616680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 616744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 616844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 616980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack frame on entry. 617080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // sp[0]: right string 617180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // sp[4]: left string 61720d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ Ldrd(r0 , r1, MemOperand(sp)); // Load right in r0, left in r1. 617380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 617480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label not_same; 617580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r0, r1); 617680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, ¬_same); 617780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(EQUAL == 0); 617880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 617980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(Smi::FromInt(EQUAL))); 618044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_compare_native(), 1, r1, r2); 618180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(sp, sp, Operand(2 * kPointerSize)); 618280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 618380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 618480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(¬_same); 618580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 618644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Check that both objects are sequential ASCII strings. 61870d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ JumpIfNotBothSequentialAsciiStrings(r1, r0, r2, r3, &runtime); 618880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 618944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Compare flat ASCII strings natively. Remove arguments from stack first. 619044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_compare_native(), 1, r2, r3); 619180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(sp, sp, Operand(2 * kPointerSize)); 61920d5e116f6aee03185f237311a943491bb079a768Kristian Monsen GenerateCompareFlatAsciiStrings(masm, r1, r0, r2, r3, r4, r5); 619380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 619480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 619580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // tagged as a small integer. 619680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&runtime); 619780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 619880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 619980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 620080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 620180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringAddStub::Generate(MacroAssembler* masm) { 62023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label call_runtime, call_builtin; 6203e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Builtins::JavaScript builtin_id = Builtins::ADD; 6204e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 620544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 620644f0eee88ff00398ff7f715fab053374d808c90dSteve Block 620780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Stack on entry: 6208e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // sp[0]: second argument (right). 6209e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // sp[4]: first argument (left). 621080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 621180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load the two arguments. 621280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument. 621380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument. 621480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 621580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Make sure that both arguments are strings if not known in advance. 6216e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (flags_ == NO_STRING_ADD_FLAGS) { 62173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfEitherSmi(r0, r1, &call_runtime); 621880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Load instance types. 621980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); 622080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); 622180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); 622280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); 622380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kStringTag == 0); 622480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If either is not a string, go to runtime. 622580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(r4, Operand(kIsNotStringMask)); 622680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(r5, Operand(kIsNotStringMask), eq); 62273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &call_runtime); 6228e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else { 6229e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Here at least one of the arguments is definitely a string. 6230e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // We convert the one that is not known to be a string. 6231e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { 6232e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); 6233e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateConvertArgument( 6234e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch masm, 1 * kPointerSize, r0, r2, r3, r4, r5, &call_builtin); 6235e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch builtin_id = Builtins::STRING_ADD_RIGHT; 6236e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { 6237e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); 6238e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch GenerateConvertArgument( 6239e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch masm, 0 * kPointerSize, r1, r2, r3, r4, r5, &call_builtin); 6240e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch builtin_id = Builtins::STRING_ADD_LEFT; 6241e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 624280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 624380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 624480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both arguments are strings. 624580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0: first string 624680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1: second string 6247e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) 6248e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) 624980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen { 625080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label strings_not_empty; 625180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if either of the strings are empty. In that case return the other. 625280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r2, FieldMemOperand(r0, String::kLengthOffset)); 625380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r3, FieldMemOperand(r1, String::kLengthOffset)); 625480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 625580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r2, Operand(Smi::FromInt(0))); // Test if first string is empty. 625680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(r1), LeaveCC, eq); // If first is empty, return second. 625780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSmiTag == 0); 625880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Else test if second string is empty. 625980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r3, Operand(Smi::FromInt(0)), ne); 626080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &strings_not_empty); // If either string was empty, return r0. 626180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 626244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1, r2, r3); 626380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(sp, sp, Operand(2 * kPointerSize)); 626480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 626580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 626680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&strings_not_empty); 626780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 626880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 626980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r2, Operand(r2, ASR, kSmiTagSize)); 627080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r3, Operand(r3, ASR, kSmiTagSize)); 627180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Both strings are non-empty. 627280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0: first string 627380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1: second string 627480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: length of first string 627580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r3: length of second string 6276e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) 6277e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) 627880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Look at the length of the result of adding the two strings. 627980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label string_add_flat_result, longer_than_two; 628080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Adding two lengths can't overflow. 628180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2); 628280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(r6, r2, Operand(r3)); 628344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Use the symbol table when adding two one character strings, as it 628444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // helps later optimizations to return a symbol here. 628580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r6, Operand(2)); 628680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &longer_than_two); 628780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 628844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Check that both strings are non-external ASCII strings. 6289e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (flags_ != NO_STRING_ADD_FLAGS) { 629080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); 629180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); 629280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); 629380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); 629480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 629580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r7, 62963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &call_runtime); 629780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 629880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Get the two characters forming the sub string. 629980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); 630080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(r3, FieldMemOperand(r1, SeqAsciiString::kHeaderSize)); 630180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 630280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Try to lookup two character string in symbol table. If it is not found 630380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // just allocate a new one. 630480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label make_two_character_string; 630580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateTwoCharacterSymbolTableProbe( 630680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen masm, r2, r3, r6, r7, r4, r5, r9, &make_two_character_string); 630744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1, r2, r3); 630880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(sp, sp, Operand(2 * kPointerSize)); 630980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 631080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 631180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&make_two_character_string); 631280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Resulting string has length 2 and first chars of two strings 631380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // are combined into single halfword in r2 register. 631480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // So we can fill resulting string without two loops by a single 631580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // halfword store instruction (which assumes that processor is 631680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // in a little endian mode) 631780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r6, Operand(2)); 63183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime); 631980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ strh(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); 632044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1, r2, r3); 632180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(sp, sp, Operand(2 * kPointerSize)); 632280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 632380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 632480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&longer_than_two); 632580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check if resulting string will be flat. 63263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(r6, Operand(ConsString::kMinLength)); 632780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(lt, &string_add_flat_result); 632880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Handle exceptionally long strings in the runtime system. 632980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); 633080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(IsPowerOf2(String::kMaxLength + 1)); 633180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. 633280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r6, Operand(String::kMaxLength + 1)); 63333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(hs, &call_runtime); 633480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 633580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If result is not supposed to be flat, allocate a cons string object. 633644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // If both strings are ASCII the result is an ASCII cons string. 6337e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (flags_ != NO_STRING_ADD_FLAGS) { 633880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); 633980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); 634080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); 634180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); 634280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 634380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label non_ascii, allocated, ascii_data; 634480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kTwoByteStringTag == 0); 634580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(r4, Operand(kStringEncodingMask)); 634680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(r5, Operand(kStringEncodingMask), ne); 634780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &non_ascii); 634880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 634980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate an ASCII cons string. 635080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&ascii_data); 63513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateAsciiConsString(r7, r6, r4, r5, &call_runtime); 635280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&allocated); 635380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Fill the fields of the cons string. 635480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r0, FieldMemOperand(r7, ConsString::kFirstOffset)); 635580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ str(r1, FieldMemOperand(r7, ConsString::kSecondOffset)); 635680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ mov(r0, Operand(r7)); 635744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1, r2, r3); 635880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(sp, sp, Operand(2 * kPointerSize)); 635980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 636080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 636180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_ascii); 636280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // At least one of the strings is two-byte. Check whether it happens 636344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // to contain only ASCII characters. 636480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r4: first instance type. 636580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r5: second instance type. 636680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(r4, Operand(kAsciiDataHintMask)); 636780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(r5, Operand(kAsciiDataHintMask), ne); 636880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(ne, &ascii_data); 636980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ eor(r4, r4, Operand(r5)); 637080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); 637180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ and_(r4, r4, Operand(kAsciiStringTag | kAsciiDataHintTag)); 637280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ cmp(r4, Operand(kAsciiStringTag | kAsciiDataHintTag)); 637380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &ascii_data); 637480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 637580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Allocate a two byte cons string. 63763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateTwoByteConsString(r7, r6, r4, r5, &call_runtime); 637780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ jmp(&allocated); 637880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 63793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // We cannot encounter sliced strings or cons strings here since: 63803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength); 63813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Handle creating a flat result from either external or sequential strings. 63823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Locate the first characters' locations. 638380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r0: first string 638480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r1: second string 638580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: length of first string 638680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r3: length of second string 6387e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) 6388e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) 638980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r6: sum of lengths. 63903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label first_prepared, second_prepared; 639180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&string_add_flat_result); 6392e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (flags_ != NO_STRING_ADD_FLAGS) { 639380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); 639480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); 639580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); 639680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); 639780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 63983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 63993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Check whether both strings have same encoding 64003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ eor(r7, r4, Operand(r5)); 64013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ tst(r7, Operand(kStringEncodingMask)); 64023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &call_runtime); 64033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 640480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STATIC_ASSERT(kSeqStringTag == 0); 640580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ tst(r4, Operand(kStringRepresentationMask)); 64063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); 64073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r7, 64083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r0, 64093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag), 64103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch LeaveCC, 64113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch eq); 64123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &first_prepared); 64133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // External string: rule out short external string and load string resource. 64143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kShortExternalStringTag != 0); 64153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ tst(r4, Operand(kShortExternalStringMask)); 64163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &call_runtime); 64173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r7, FieldMemOperand(r0, ExternalString::kResourceDataOffset)); 64183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&first_prepared); 64193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 64203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kSeqStringTag == 0); 64213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ tst(r5, Operand(kStringRepresentationMask)); 64223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); 64233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r1, 64243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r1, 64253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag), 64263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch LeaveCC, 64273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch eq); 64283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &second_prepared); 64293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // External string: rule out short external string and load string resource. 64303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kShortExternalStringTag != 0); 64313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ tst(r5, Operand(kShortExternalStringMask)); 64323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &call_runtime); 64333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r1, FieldMemOperand(r1, ExternalString::kResourceDataOffset)); 64343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&second_prepared); 64353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 64363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label non_ascii_string_add_flat_result; 64373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r7: first character of first string 64383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r1: first character of second string 643980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: length of first string. 644080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r3: length of second string. 64413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r6: sum of lengths. 64423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Both strings have the same encoding. 64433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kTwoByteStringTag == 0); 64443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ tst(r5, Operand(kStringEncodingMask)); 644580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ b(eq, &non_ascii_string_add_flat_result); 644680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 64473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime); 64483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r6, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 64493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r0: result string. 64503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r7: first character of first string. 64513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r1: first character of second string. 645280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: length of first string. 645380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r3: length of second string. 645480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r6: first character of result. 64553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch StringHelper::GenerateCopyCharacters(masm, r6, r7, r2, r4, true); 645680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r6: next character of result. 645780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, true); 645844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1, r2, r3); 645980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(sp, sp, Operand(2 * kPointerSize)); 646080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 646180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 646280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&non_ascii_string_add_flat_result); 64633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ AllocateTwoByteString(r0, r6, r4, r5, r9, &call_runtime); 64643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r6, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 64653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r0: result string. 64663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r7: first character of first string. 64673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r1: first character of second string. 646880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r2: length of first string. 646980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r3: length of second string. 647080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // r6: first character of result. 64713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch StringHelper::GenerateCopyCharacters(masm, r6, r7, r2, r4, false); 64723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // r6: next character of result. 647380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, false); 647444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->string_add_native(), 1, r2, r3); 647580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ add(sp, sp, Operand(2 * kPointerSize)); 647680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ Ret(); 647780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 647880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Just jump to runtime to add the two strings. 64793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&call_runtime); 648080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ TailCallRuntime(Runtime::kStringAdd, 2, 1); 6481e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 6482e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (call_builtin.is_linked()) { 6483e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&call_builtin); 6484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); 6485e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch } 6486e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch} 6487e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 6488e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 6489e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid StringAddStub::GenerateConvertArgument(MacroAssembler* masm, 6490e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch int stack_offset, 6491e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register arg, 6492e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch1, 6493e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch2, 6494e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch3, 6495e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register scratch4, 6496e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label* slow) { 6497e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // First check if the argument is already a string. 6498e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label not_string, done; 6499e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ JumpIfSmi(arg, ¬_string); 6500e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ CompareObjectType(arg, scratch1, scratch1, FIRST_NONSTRING_TYPE); 6501e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(lt, &done); 6502e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 6503e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Check the number to string cache. 6504e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Label not_cached; 6505e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(¬_string); 6506e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Puts the cached result into scratch1. 6507e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch NumberToStringStub::GenerateLookupNumberStringCache(masm, 6508e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch arg, 6509e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch1, 6510e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch2, 6511e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch3, 6512e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch4, 6513e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch false, 6514e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ¬_cached); 6515e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(arg, scratch1); 6516e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ str(arg, MemOperand(sp, stack_offset)); 6517e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ jmp(&done); 6518e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 6519e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Check if the argument is a safe string wrapper. 6520e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(¬_cached); 6521e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ JumpIfSmi(arg, slow); 6522e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ CompareObjectType( 6523e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch arg, scratch1, scratch2, JS_VALUE_TYPE); // map -> scratch1. 6524e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(ne, slow); 6525e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitField2Offset)); 6526e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ and_(scratch2, 6527e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch scratch2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); 6528e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ cmp(scratch2, 6529e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); 6530e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ b(ne, slow); 6531e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ ldr(arg, FieldMemOperand(arg, JSValue::kValueOffset)); 6532e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ str(arg, MemOperand(sp, stack_offset)); 6533e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 6534e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ bind(&done); 653580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 653680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 653780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 6538b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateSmis(MacroAssembler* masm) { 6539b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(state_ == CompareIC::SMIS); 6540b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label miss; 6541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ orr(r2, r1, r0); 65423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfNotSmi(r2, &miss); 6543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (GetCondition() == eq) { 6545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // For equality we do not care about the sign of the result. 6546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(r0, r0, r1, SetCC); 6547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 65481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Untag before subtracting to avoid handling overflow. 65491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiUntag(r1); 65501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ sub(r0, r1, SmiUntagOperand(r0)); 6551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 6552b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 6553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&miss); 6555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateMiss(masm); 6556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 6557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { 6560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(state_ == CompareIC::HEAP_NUMBERS); 6561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label generic_stub; 65633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label unordered, maybe_undefined1, maybe_undefined2; 6564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label miss; 6565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ and_(r2, r1, Operand(r0)); 65663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(r2, &generic_stub); 6567b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CompareObjectType(r0, r2, r2, HEAP_NUMBER_TYPE); 65693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &maybe_undefined1); 6570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE); 65713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &maybe_undefined2); 6572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Inlining the double comparison and falling back to the general compare 6574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // stub if NaN is involved or VFP3 is unsupported. 65758b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (CpuFeatures::IsSupported(VFP3)) { 6576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CpuFeatures::Scope scope(VFP3); 6577b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6578b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Load left and right operand 6579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(r2, r1, Operand(kHeapObjectTag)); 6580b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ vldr(d0, r2, HeapNumber::kValueOffset); 6581b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(r2, r0, Operand(kHeapObjectTag)); 6582b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ vldr(d1, r2, HeapNumber::kValueOffset); 6583b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Compare operands 6585b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ VFPCompareAndSetFlags(d0, d1); 6586b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6587b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Don't base result on status bits when a NaN is involved. 6588b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ b(vs, &unordered); 6589b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6590b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Return a result of -1, 0, or 1, based on status bits. 6591b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(r0, Operand(EQUAL), LeaveCC, eq); 6592b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(r0, Operand(LESS), LeaveCC, lt); 6593b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ mov(r0, Operand(GREATER), LeaveCC, gt); 6594b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 6595b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 6596b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 65973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&unordered); 6598b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0); 6599b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&generic_stub); 6600b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); 6601b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 66023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&maybe_undefined1); 66033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (Token::IsOrderedRelationalCompareOp(op_)) { 66043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(r0, Heap::kUndefinedValueRootIndex); 66053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &miss); 66063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE); 66073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &maybe_undefined2); 66083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ jmp(&unordered); 66093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 66103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 66113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&maybe_undefined2); 66123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (Token::IsOrderedRelationalCompareOp(op_)) { 66133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CompareRoot(r1, Heap::kUndefinedValueRootIndex); 66143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &unordered); 66153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 66163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6617b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&miss); 6618b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateMiss(masm); 6619b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 6620b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6621b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateSymbols(MacroAssembler* masm) { 6623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(state_ == CompareIC::SYMBOLS); 6624257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 6625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 6627257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = r1; 6628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = r0; 6629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp1 = r2; 6630257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp2 = r3; 6631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6632257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are heap objects. 6633257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfEitherSmi(left, right, &miss); 6634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are symbols. 6636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); 6637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); 6638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); 6639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); 6640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSymbolTag != 0); 6641257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(tmp1, tmp1, Operand(tmp2)); 6642257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ tst(tmp1, Operand(kIsSymbolMask)); 6643257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(eq, &miss); 6644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Symbols are compared by identity. 6646257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(left, right); 6647257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Make sure r0 is non-zero. At this point input operands are 6648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // guaranteed to be non-zero. 6649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(right.is(r0)); 6650257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(EQUAL == 0); 6651257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 6652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); 6653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Ret(); 6654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&miss); 6656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateMiss(masm); 6657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateStrings(MacroAssembler* masm) { 6661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(state_ == CompareIC::STRINGS); 6662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label miss; 6663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 66643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch bool equality = Token::IsEqualityOp(op_); 66653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers containing left and right operands respectively. 6667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register left = r1; 6668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register right = r0; 6669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp1 = r2; 6670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp2 = r3; 6671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp3 = r4; 6672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp4 = r5; 6673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are heap objects. 6675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ JumpIfEitherSmi(left, right, &miss); 6676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both operands are strings. This leaves the instance 6678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // types loaded in tmp1 and tmp2. 6679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); 6680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); 6681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); 6682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); 6683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kNotStringTag != 0); 6684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ orr(tmp3, tmp1, tmp2); 6685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ tst(tmp3, Operand(kIsNotStringMask)); 6686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(ne, &miss); 6687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Fast check for identical strings. 6689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(left, right); 6690257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(EQUAL == 0); 6691257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch STATIC_ASSERT(kSmiTag == 0); 6692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); 6693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Ret(eq); 6694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle not identical strings. 6696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both strings are symbols. If they are, we're done 6698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // because we already know they are not identical. 66993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (equality) { 67003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(GetCondition() == eq); 67013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch STATIC_ASSERT(kSymbolTag != 0); 67023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(tmp3, tmp1, Operand(tmp2)); 67033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ tst(tmp3, Operand(kIsSymbolMask)); 67043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Make sure r0 is non-zero. At this point input operands are 67053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // guaranteed to be non-zero. 67063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(right.is(r0)); 67073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(ne); 67083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 6709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6710257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check that both strings are sequential ASCII. 6711257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label runtime; 67123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfBothInstanceTypesAreNotSequentialAscii( 67133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch tmp1, tmp2, tmp3, tmp4, &runtime); 6714257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6715257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compare flat ASCII strings. Returns when done. 67163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (equality) { 67173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch StringCompareStub::GenerateFlatAsciiStringEquals( 67183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm, left, right, tmp1, tmp2, tmp3); 67193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 67203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch StringCompareStub::GenerateCompareFlatAsciiStrings( 67213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm, left, right, tmp1, tmp2, tmp3, tmp4); 67223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 6723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Handle more complex cases in runtime. 6725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&runtime); 6726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Push(left, right); 67273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (equality) { 67283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kStringEquals, 2, 1); 67293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 67303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 67313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 6732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&miss); 6734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch GenerateMiss(masm); 6735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6738b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateObjects(MacroAssembler* masm) { 6739b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(state_ == CompareIC::OBJECTS); 6740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label miss; 6741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ and_(r2, r1, Operand(r0)); 67423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch __ JumpIfSmi(r2, &miss); 6743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE); 6745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ b(ne, &miss); 6746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE); 6747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ b(ne, &miss); 6748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(GetCondition() == eq); 6750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ sub(r0, r0, Operand(r1)); 6751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Ret(); 6752b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&miss); 6754b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch GenerateMiss(masm); 6755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 6756b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6757b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 67583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) { 67593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label miss; 67603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ and_(r2, r1, Operand(r0)); 67613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfSmi(r2, &miss); 67623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); 67633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); 67643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(r2, Operand(known_map_)); 67653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &miss); 67663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(r3, Operand(known_map_)); 67673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(ne, &miss); 67683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 67693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sub(r0, r0, Operand(r1)); 67703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(); 67713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 67723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&miss); 67733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateMiss(masm); 67743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 67753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 67763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 67773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6778c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdochvoid ICCompareStub::GenerateMiss(MacroAssembler* masm) { 67793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 67803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Call the runtime system in a fresh internal frame. 67813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference miss = 67823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate()); 67833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 67843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch FrameScope scope(masm, StackFrame::INTERNAL); 67853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Push(r1, r0); 67863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(lr); 67873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Push(r1, r0); 67883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(ip, Operand(Smi::FromInt(op_))); 67893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(ip); 67903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallExternalReference(miss, 3); 67913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Compute the entry point of the rewritten stub. 67923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag)); 67933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Restore registers. 67943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(lr); 67953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(r0); 67963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(r1); 67973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 6798c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch 6799b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Jump(r2); 6800b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 6801b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 6802b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 68031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid DirectCEntryStub::Generate(MacroAssembler* masm) { 68041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ldr(pc, MemOperand(sp, 0)); 68051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 68061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 68071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 68081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid DirectCEntryStub::GenerateCall(MacroAssembler* masm, 6809e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch ExternalReference function) { 6810e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(r2, Operand(function)); 681169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch GenerateCall(masm, r2); 68121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 68131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 68141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 6815e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid DirectCEntryStub::GenerateCall(MacroAssembler* masm, 6816e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Register target) { 6817e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ mov(lr, Operand(reinterpret_cast<intptr_t>(GetCode().location()), 6818e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch RelocInfo::CODE_TARGET)); 6819e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Push return address (accessible to GC through exit frame pc). 682069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch // Note that using pc with str is deprecated. 682169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch Label start; 682269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ bind(&start); 682369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ add(ip, pc, Operand(Assembler::kInstrSize)); 682469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ str(ip, MemOperand(sp, 0)); 6825e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Jump(target); // Call the C++ function. 682669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch ASSERT_EQ(Assembler::kInstrSize + Assembler::kPcLoadDelta, 682769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch masm->SizeOfCodeGeneratedSince(&start)); 6828e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch} 6829e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 6830e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 68313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, 68323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label* miss, 68333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label* done, 68343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Register receiver, 68353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Register properties, 68363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Handle<String> name, 68373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Register scratch0) { 6838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If names of slots in range from 1 to kProbes - 1 for the hash value are 6839257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // not equal to the name and kProbes-th slot is not used (its name is the 6840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // undefined value), it guarantees the hash table doesn't contain the 6841257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // property. It's true even if some slots represent deleted properties 68423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // (their names are the hole value). 6843257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = 0; i < kInlinedProbes; i++) { 6844257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // scratch0 points to properties hash. 6845257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 6846257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register index = scratch0; 6847257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Capacity is smi 2^n. 6848257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(index, FieldMemOperand(properties, kCapacityOffset)); 6849257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sub(index, index, Operand(1)); 6850257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(index, index, Operand( 6851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Smi::FromInt(name->Hash() + StringDictionary::GetProbeOffset(i)))); 6852257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6853257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the entry size. 6854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 6855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(index, index, Operand(index, LSL, 1)); // index *= 3. 6856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register entity_name = scratch0; 6858257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Having undefined at this place means the name is not contained. 6859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT_EQ(kSmiTagSize, 1); 6860257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register tmp = properties; 6861257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(tmp, properties, Operand(index, LSL, 1)); 6862257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset)); 6863257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(!tmp.is(entity_name)); 6865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex); 6866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(entity_name, tmp); 6867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(eq, done); 6868257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6869257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i != kInlinedProbes - 1) { 68703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Load the hole ready for use below: 68713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ LoadRoot(tmp, Heap::kTheHoleValueRootIndex); 68723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6873257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Stop if found the property. 6874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(entity_name, Operand(Handle<String>(name))); 6875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(eq, miss); 6876257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 68773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label the_hole; 68783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(entity_name, tmp); 68793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(eq, &the_hole); 68803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6881257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the entry name is not a symbol. 6882257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); 6883257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldrb(entity_name, 6884257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); 6885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ tst(entity_name, Operand(kIsSymbolMask)); 6886257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(eq, miss); 6887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 68883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&the_hole); 68893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Restore the properties. 6891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(properties, 6892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch FieldMemOperand(receiver, JSObject::kPropertiesOffset)); 6893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const int spill_mask = 6897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch (lr.bit() | r6.bit() | r5.bit() | r4.bit() | r3.bit() | 6898257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r2.bit() | r1.bit() | r0.bit()); 6899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ stm(db_w, sp, spill_mask); 6901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(r0, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); 6902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(r1, Operand(Handle<String>(name))); 6903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionaryLookupStub stub(NEGATIVE_LOOKUP); 69043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallStub(&stub); 69053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(r0, Operand(0)); 6906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldm(ia_w, sp, spill_mask); 6907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(eq, done); 6909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(ne, miss); 6910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Probe the string dictionary in the |elements| register. Jump to the 6914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// |done| label if a property with the given name is found. Jump to 6915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// the |miss| label otherwise. 6916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// If lookup was successful |scratch2| will be equal to elements + 4 * index. 6917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, 6918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* miss, 6919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label* done, 6920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register elements, 6921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register name, 6922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch1, 6923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register scratch2) { 69243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(!elements.is(scratch1)); 69253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(!elements.is(scratch2)); 69263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(!name.is(scratch1)); 69273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(!name.is(scratch2)); 69283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Assert that name contains a string. 6930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (FLAG_debug_code) __ AbortIfNotString(name); 6931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6932257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the capacity mask. 6933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset)); 6934257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch1, Operand(scratch1, ASR, kSmiTagSize)); // convert smi to int 6935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sub(scratch1, scratch1, Operand(1)); 6936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6937257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Generate an unrolled loop that performs a few probes before 6938257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // giving up. Measurements done on Gmail indicate that 2 probes 6939257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // cover ~93% of loads from dictionaries. 6940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = 0; i < kInlinedProbes; i++) { 6941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 6942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(scratch2, FieldMemOperand(name, String::kHashFieldOffset)); 6943257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i > 0) { 6944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Add the probe offset (i + i * i) left shifted to avoid right shifting 6945257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // the hash in a separate instruction. The value hash + i + i * i is right 6946257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // shifted in the following and instruction. 6947257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::GetProbeOffset(i) < 6948257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1 << (32 - String::kHashFieldOffset)); 6949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(scratch2, scratch2, Operand( 6950257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionary::GetProbeOffset(i) << String::kHashShift)); 6951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(scratch2, scratch1, Operand(scratch2, LSR, String::kHashShift)); 6953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the element size. 6955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 6956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // scratch2 = scratch2 * 3. 6957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(scratch2, scratch2, Operand(scratch2, LSL, 1)); 6958257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6959257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the key is identical to the name. 6960257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(scratch2, elements, Operand(scratch2, LSL, 2)); 6961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset)); 6962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(name, Operand(ip)); 6963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(eq, done); 6964257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 6965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch const int spill_mask = 6967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch (lr.bit() | r6.bit() | r5.bit() | r4.bit() | 6968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r3.bit() | r2.bit() | r1.bit() | r0.bit()) & 6969257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ~(scratch1.bit() | scratch2.bit()); 6970257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6971257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ stm(db_w, sp, spill_mask); 69723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (name.is(r0)) { 69733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(!elements.is(r1)); 69743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Move(r1, name); 69753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Move(r0, elements); 69763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 69773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Move(r0, elements); 69783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Move(r1, name); 69793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 6980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionaryLookupStub stub(POSITIVE_LOOKUP); 6981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ CallStub(&stub); 69823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ cmp(r0, Operand(0)); 6983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(scratch2, Operand(r2)); 6984257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldm(ia_w, sp, spill_mask); 6985257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6986257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(ne, done); 6987257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(eq, miss); 6988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 6989257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6990257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 6991257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::Generate(MacroAssembler* masm) { 69923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // This stub overrides SometimesSetsUpAFrame() to return false. That means 69933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // we cannot call anything that could cause a GC from this stub. 6994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Registers: 6995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // result: StringDictionary to probe 6996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // r1: key 6997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // : StringDictionary to probe. 6998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // index_: will hold an index of entry if lookup is successful. 6999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // might alias with result_. 7000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Returns: 7001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // result_ is zero if lookup failed, non zero otherwise. 7002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register result = r0; 7004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register dictionary = r0; 7005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register key = r1; 7006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register index = r2; 7007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register mask = r3; 7008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register hash = r4; 7009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register undefined = r5; 7010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Register entry_key = r6; 7011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch Label in_dictionary, maybe_in_dictionary, not_in_dictionary; 7013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(mask, FieldMemOperand(dictionary, kCapacityOffset)); 7015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(mask, Operand(mask, ASR, kSmiTagSize)); 7016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ sub(mask, mask, Operand(1)); 7017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset)); 7019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex); 7021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for (int i = kInlinedProbes; i < kTotalProbes; i++) { 7023257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 7024257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Capacity is smi 2^n. 7025257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i > 0) { 7026257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Add the probe offset (i + i * i) left shifted to avoid right shifting 7027257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // the hash in a separate instruction. The value hash + i + i * i is right 7028257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // shifted in the following and instruction. 7029257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::GetProbeOffset(i) < 7030257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1 << (32 - String::kHashFieldOffset)); 7031257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(index, hash, Operand( 7032257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch StringDictionary::GetProbeOffset(i) << String::kHashShift)); 7033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 7034257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(index, Operand(hash)); 7035257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 7036257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ and_(index, mask, Operand(index, LSR, String::kHashShift)); 7037257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7038257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Scale the index by multiplying by the entry size. 7039257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 7040257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(index, index, Operand(index, LSL, 1)); // index *= 3. 7041257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7042257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ASSERT_EQ(kSmiTagSize, 1); 7043257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ add(index, dictionary, Operand(index, LSL, 2)); 7044257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(entry_key, FieldMemOperand(index, kElementsStartOffset)); 7045257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7046257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Having undefined at this place means the name is not contained. 7047257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(entry_key, Operand(undefined)); 7048257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(eq, ¬_in_dictionary); 7049257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7050257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Stop if found the property. 7051257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ cmp(entry_key, Operand(key)); 7052257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(eq, &in_dictionary); 7053257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7054257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { 7055257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // Check if the entry name is not a symbol. 7056257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset)); 7057257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ ldrb(entry_key, 7058257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch FieldMemOperand(entry_key, Map::kInstanceTypeOffset)); 7059257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ tst(entry_key, Operand(kIsSymbolMask)); 7060257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ b(eq, &maybe_in_dictionary); 7061257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 7062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 7063257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7064257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&maybe_in_dictionary); 7065257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // If we are doing negative lookup then probing failure should be 7066257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // treated as a lookup success. For positive lookup probing failure 7067257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // should be treated as lookup failure. 7068257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (mode_ == POSITIVE_LOOKUP) { 706969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(result, Operand::Zero()); 7070257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Ret(); 7071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 7072257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(&in_dictionary); 7074257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ mov(result, Operand(1)); 7075257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Ret(); 7076257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7077257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ bind(¬_in_dictionary); 707869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch __ mov(result, Operand::Zero()); 7079257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch __ Ret(); 7080257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 7081257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 7082257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 70833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstruct AheadOfTimeWriteBarrierStubList { 70843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Register object, value, address; 70853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch RememberedSetAction action; 70863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}; 70873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 70883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#define REG(Name) { kRegister_ ## Name ## _Code } 70893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 70903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { 70913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Used in RegExpExecStub. 70923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r6), REG(r4), REG(r7), EMIT_REMEMBERED_SET }, 70933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r6), REG(r2), REG(r7), EMIT_REMEMBERED_SET }, 70943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Used in CompileArrayPushCall. 70953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Also used in StoreIC::GenerateNormal via GenerateDictionaryStore. 70963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Also used in KeyedStoreIC::GenerateGeneric. 70973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r3), REG(r4), REG(r5), EMIT_REMEMBERED_SET }, 70983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Used in CompileStoreGlobal. 70993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r4), REG(r1), REG(r2), OMIT_REMEMBERED_SET }, 71003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Used in StoreStubCompiler::CompileStoreField via GenerateStoreField. 71013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r1), REG(r2), REG(r3), EMIT_REMEMBERED_SET }, 71023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r3), REG(r2), REG(r1), EMIT_REMEMBERED_SET }, 71033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Used in KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField. 71043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r2), REG(r1), REG(r3), EMIT_REMEMBERED_SET }, 71053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r3), REG(r1), REG(r2), EMIT_REMEMBERED_SET }, 71063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // KeyedStoreStubCompiler::GenerateStoreFastElement. 71073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r3), REG(r2), REG(r4), EMIT_REMEMBERED_SET }, 71083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r2), REG(r3), REG(r4), EMIT_REMEMBERED_SET }, 71093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ElementsTransitionGenerator::GenerateSmiOnlyToObject 71103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble 71113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // and ElementsTransitionGenerator::GenerateDoubleToObject 71123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r2), REG(r3), REG(r9), EMIT_REMEMBERED_SET }, 71133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r2), REG(r3), REG(r9), OMIT_REMEMBERED_SET }, 71143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ElementsTransitionGenerator::GenerateDoubleToObject 71153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r6), REG(r2), REG(r0), EMIT_REMEMBERED_SET }, 71163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r2), REG(r6), REG(r9), EMIT_REMEMBERED_SET }, 71173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // StoreArrayLiteralElementStub::Generate 71183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(r5), REG(r0), REG(r6), EMIT_REMEMBERED_SET }, 71193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Null termination. 71203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { REG(no_reg), REG(no_reg), REG(no_reg), EMIT_REMEMBERED_SET} 71213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}; 71223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#undef REG 71243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool RecordWriteStub::IsPregenerated() { 71263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; 71273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch !entry->object.is(no_reg); 71283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch entry++) { 71293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (object_.is(entry->object) && 71303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch value_.is(entry->value) && 71313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch address_.is(entry->address) && 71323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch remembered_set_action_ == entry->action && 71333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch save_fp_regs_mode_ == kDontSaveFPRegs) { 71343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return true; 71353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 71363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 71373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return false; 71383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 71393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool StoreBufferOverflowStub::IsPregenerated() { 71423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return save_doubles_ == kDontSaveFPRegs || ISOLATE->fp_stubs_generated(); 71433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 71443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime() { 71473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch StoreBufferOverflowStub stub1(kDontSaveFPRegs); 71483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch stub1.GetCode()->set_is_pregenerated(true); 71493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 71503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::GenerateFixedRegStubsAheadOfTime() { 71533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; 71543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch !entry->object.is(no_reg); 71553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch entry++) { 71563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch RecordWriteStub stub(entry->object, 71573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch entry->value, 71583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch entry->address, 71593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch entry->action, 71603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kDontSaveFPRegs); 71613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch stub.GetCode()->set_is_pregenerated(true); 71623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 71633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 71643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Takes the input in 3 registers: address_ value_ and object_. A pointer to 71673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// the value has just been written into the object, now this stub makes sure 71683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// we keep the GC informed. The word in the object where the value has been 71693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// written is in the address register. 71703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::Generate(MacroAssembler* masm) { 71713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label skip_to_incremental_noncompacting; 71723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label skip_to_incremental_compacting; 71733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // The first two instructions are generated with labels so as to get the 71753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // offset fixed up correctly by the bind(Label*) call. We patch it back and 71763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // forth between a compare instructions (a nop in this position) and the 71773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // real branch when we start and stop incremental heap marking. 71783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // See RecordWriteStub::Patch for details. 71793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(&skip_to_incremental_noncompacting); 71803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ b(&skip_to_incremental_compacting); 71813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (remembered_set_action_ == EMIT_REMEMBERED_SET) { 71833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ RememberedSetHelper(object_, 71843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch address_, 71853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch value_, 71863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch save_fp_regs_mode_, 71873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler::kReturnAtEnd); 71883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 71893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(); 71903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&skip_to_incremental_noncompacting); 71923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateIncremental(masm, INCREMENTAL); 71933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&skip_to_incremental_compacting); 71953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GenerateIncremental(masm, INCREMENTAL_COMPACTION); 71963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 71973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Initial mode of the stub is expected to be STORE_BUFFER_ONLY. 71983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Will be checked in IncrementalMarking::ActivateGeneratedStub. 71993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(Assembler::GetBranchOffset(masm->instr_at(0)) < (1 << 12)); 72003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(Assembler::GetBranchOffset(masm->instr_at(4)) < (1 << 12)); 72013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch PatchBranchIntoNop(masm, 0); 72023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch PatchBranchIntoNop(masm, Assembler::kInstrSize); 72033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 72043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) { 72073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.Save(masm); 72083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (remembered_set_action_ == EMIT_REMEMBERED_SET) { 72103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label dont_need_remembered_set; 72113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(regs_.scratch0(), MemOperand(regs_.address(), 0)); 72133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfNotInNewSpace(regs_.scratch0(), // Value. 72143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.scratch0(), 72153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &dont_need_remembered_set); 72163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CheckPageFlag(regs_.object(), 72183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.scratch0(), 72193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1 << MemoryChunk::SCAN_ON_SCAVENGE, 72203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ne, 72213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &dont_need_remembered_set); 72223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // First notify the incremental marker if necessary, then update the 72243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // remembered set. 72253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CheckNeedsToInformIncrementalMarker( 72263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode); 72273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch InformIncrementalMarker(masm, mode); 72283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.Restore(masm); 72293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ RememberedSetHelper(object_, 72303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch address_, 72313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch value_, 72323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch save_fp_regs_mode_, 72333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler::kReturnAtEnd); 72343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&dont_need_remembered_set); 72363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 72373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CheckNeedsToInformIncrementalMarker( 72393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm, kReturnOnNoNeedToInformIncrementalMarker, mode); 72403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch InformIncrementalMarker(masm, mode); 72413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.Restore(masm); 72423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(); 72433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 72443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) { 72473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_); 72483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int argument_count = 3; 72493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ PrepareCallCFunction(argument_count, regs_.scratch0()); 72503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Register address = 72513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r0.is(regs_.address()) ? regs_.scratch0() : regs_.address(); 72523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(!address.is(regs_.object())); 72533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(!address.is(r0)); 72543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Move(address, regs_.address()); 72553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Move(r0, regs_.object()); 72563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (mode == INCREMENTAL_COMPACTION) { 72573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Move(r1, address); 72583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 72593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(mode == INCREMENTAL); 72603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r1, MemOperand(address, 0)); 72613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 72623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(r2, Operand(ExternalReference::isolate_address())); 72633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch AllowExternalCallThatCantCauseGC scope(masm); 72653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (mode == INCREMENTAL_COMPACTION) { 72663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallCFunction( 72673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference::incremental_evacuation_record_write_function( 72683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm->isolate()), 72693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch argument_count); 72703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 72713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(mode == INCREMENTAL); 72723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallCFunction( 72733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ExternalReference::incremental_marking_record_write_function( 72743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch masm->isolate()), 72753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch argument_count); 72763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 72773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_); 72783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 72793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::CheckNeedsToInformIncrementalMarker( 72823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler* masm, 72833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch OnNoNeedToInformIncrementalMarker on_no_need, 72843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Mode mode) { 72853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label on_black; 72863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label need_incremental; 72873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label need_incremental_pop_scratch; 72883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Let's look at the color of the object: If it is not black we don't have 72903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // to inform the incremental marker. 72913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black); 72923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 72933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.Restore(masm); 72943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { 72953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ RememberedSetHelper(object_, 72963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch address_, 72973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch value_, 72983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch save_fp_regs_mode_, 72993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler::kReturnAtEnd); 73003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 73013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(); 73023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 73033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&on_black); 73053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Get the value from the slot. 73073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(regs_.scratch0(), MemOperand(regs_.address(), 0)); 73083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (mode == INCREMENTAL_COMPACTION) { 73103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label ensure_not_white; 73113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CheckPageFlag(regs_.scratch0(), // Contains value. 73133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.scratch1(), // Scratch. 73143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MemoryChunk::kEvacuationCandidateMask, 73153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch eq, 73163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &ensure_not_white); 73173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CheckPageFlag(regs_.object(), 73193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.scratch1(), // Scratch. 73203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MemoryChunk::kSkipEvacuationSlotsRecordingMask, 73213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch eq, 73223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &need_incremental); 73233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&ensure_not_white); 73253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 73263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // We need extra registers for this, so we push the object and the address 73283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // register temporarily. 73293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Push(regs_.object(), regs_.address()); 73303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ EnsureNotWhite(regs_.scratch0(), // The value. 73313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.scratch1(), // Scratch. 73323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.object(), // Scratch. 73333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.address(), // Scratch. 73343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &need_incremental_pop_scratch); 73353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Pop(regs_.object(), regs_.address()); 73363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch regs_.Restore(masm); 73383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { 73393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ RememberedSetHelper(object_, 73403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch address_, 73413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch value_, 73423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch save_fp_regs_mode_, 73433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MacroAssembler::kReturnAtEnd); 73443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 73453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(); 73463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 73473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&need_incremental_pop_scratch); 73493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Pop(regs_.object(), regs_.address()); 73503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&need_incremental); 73523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Fall through when we need to inform the incremental marker. 73543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 73553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) { 73583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ----------- S t a t e ------------- 73593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // -- r0 : element value to store 73603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // -- r1 : array literal 73613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // -- r2 : map of array literal 73623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // -- r3 : element index as smi 73633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // -- r4 : array literal index in function as smi 73643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // ----------------------------------- 73653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label element_done; 73673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label double_elements; 73683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label smi_element; 73693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label slow_elements; 73703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label fast_elements; 73713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CheckFastElements(r2, r5, &double_elements); 73733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS 73743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ JumpIfSmi(r0, &smi_element); 73753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CheckFastSmiOnlyElements(r2, r5, &fast_elements); 73763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Store into the array literal requires a elements transition. Call into 73783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // the runtime. 73793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&slow_elements); 73803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // call. 73813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Push(r1, r3, r0); 73823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 73833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r5, FieldMemOperand(r5, JSFunction::kLiteralsOffset)); 73843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Push(r5, r4); 73853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1); 73863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Array literal has ElementsKind of FAST_ELEMENTS and value is an object. 73883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&fast_elements); 73893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset)); 73903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r6, r5, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); 73913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r6, r6, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 73923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r0, MemOperand(r6, 0)); 73933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Update the write barrier for the array store. 73943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ RecordWrite(r5, r6, r0, kLRHasNotBeenSaved, kDontSaveFPRegs, 73953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); 73963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(); 73973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 73983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or 73993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // FAST_ELEMENTS, and value is Smi. 74003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&smi_element); 74013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset)); 74023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ add(r6, r5, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); 74033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ str(r0, FieldMemOperand(r6, FixedArray::kHeaderSize)); 74043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(); 74053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 74063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS. 74073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&double_elements); 74083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset)); 74093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ StoreNumberToDoubleElements(r0, r3, r1, r5, r6, r7, r9, r2, 74103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch &slow_elements); 74113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Ret(); 74123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 74133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 741480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#undef __ 741580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 741680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} } // namespace v8::internal 741780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 741880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif // V8_TARGET_ARCH_ARM 7419