stub-cache-x64.cc revision 0d5e116f6aee03185f237311a943491bb079a768
14515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke// Copyright 2010 the V8 project authors. All rights reserved. 2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without 3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are 4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met: 5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions of source code must retain the above copyright 7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// notice, this list of conditions and the following disclaimer. 8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions in binary form must reproduce the above 9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// copyright notice, this list of conditions and the following 10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// disclaimer in the documentation and/or other materials provided 11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// with the distribution. 12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Neither the name of Google Inc. nor the names of its 13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// contributors may be used to endorse or promote products derived 14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// from this software without specific prior written permission. 15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h" 30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 31f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#if defined(V8_TARGET_ARCH_X64) 32f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke 33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "ic-inl.h" 3480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "code-stubs.h" 35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "codegen-inl.h" 36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "stub-cache.h" 3780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "macro-assembler.h" 38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 { 40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal { 41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//----------------------------------------------------------------------------- 43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// StubCompiler static helper functions 44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM(masm) 46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void ProbeTable(MacroAssembler* masm, 49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Code::Flags flags, 50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block StubCache::Table table, 51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register name, 52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register offset) { 533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block ASSERT_EQ(8, kPointerSize); 543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block ASSERT_EQ(16, sizeof(StubCache::Entry)); 553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // The offset register holds the entry offset times four (due to masking 563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // and shifting optimizations). 57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference key_offset(SCTableReference::keyReference(table)); 58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, key_offset); 61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the key in the entry matches the name. 623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Multiply entry offset by 16 to get the entry address. Since the 633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // offset register already holds the entry offset times four, multiply 643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // by a further four. 653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ cmpl(name, Operand(kScratchRegister, offset, times_4, 0)); 66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the code entry from the cache. 68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Use key_offset + kPointerSize, rather than loading value_offset. 69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, 703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Operand(kScratchRegister, offset, times_4, kPointerSize)); 71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the flags match what we're looking for. 72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movl(offset, FieldOperand(kScratchRegister, Code::kFlagsOffset)); 73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ and_(offset, Immediate(~Code::kFlagsNotUsedInLookup)); 74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpl(offset, Immediate(flags)); 75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Jump to the first instruction in the code stub. 78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ addq(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag)); 79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(kScratchRegister); 80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 853bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// Helper function used to check that the dictionary doesn't contain 863bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// the property. This function may return false negatives, so miss_label 873bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// must always call a backup property check that is complete. 883bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// This function is safe to call if the receiver has fast properties. 893bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// Name must be a symbol and receiver must be a heap object. 903bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdochstatic void GenerateDictionaryNegativeLookup(MacroAssembler* masm, 913bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Label* miss_label, 923bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register receiver, 933bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch String* name, 943bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register r0, 953bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register r1) { 963bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch ASSERT(name->IsSymbol()); 973bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ IncrementCounter(&Counters::negative_lookups, 1); 983bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ IncrementCounter(&Counters::negative_lookups_miss, 1); 993bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1003bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Label done; 1013bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(r0, FieldOperand(receiver, HeapObject::kMapOffset)); 1023bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1033bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const int kInterceptorOrAccessCheckNeededMask = 1043bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); 1053bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1063bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Bail out if the receiver has a named interceptor or requires access checks. 1073bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ testb(FieldOperand(r0, Map::kBitFieldOffset), 1083bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Immediate(kInterceptorOrAccessCheckNeededMask)); 1093bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(not_zero, miss_label); 1103bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1113bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Check that receiver is a JSObject. 1123bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ CmpInstanceType(r0, FIRST_JS_OBJECT_TYPE); 1133bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(below, miss_label); 1143bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1153bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Load properties array. 1163bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register properties = r0; 1173bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(properties, FieldOperand(receiver, JSObject::kPropertiesOffset)); 1183bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1193bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Check that the properties array is a dictionary. 1203bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset), 1213bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Heap::kHashTableMapRootIndex); 1223bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(not_equal, miss_label); 1233bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1243bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Compute the capacity mask. 1253bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const int kCapacityOffset = 1263bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch StringDictionary::kHeaderSize + 1273bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch StringDictionary::kCapacityIndex * kPointerSize; 1283bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1293bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Generate an unrolled loop that performs a few probes before 1303bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // giving up. 1313bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch static const int kProbes = 4; 1323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const int kElementsStartOffset = 1333bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch StringDictionary::kHeaderSize + 1343bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch StringDictionary::kElementsStartIndex * kPointerSize; 1353bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1363bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // If names of slots in range from 1 to kProbes - 1 for the hash value are 1373bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // not equal to the name and kProbes-th slot is not used (its name is the 1383bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // undefined value), it guarantees the hash table doesn't contain the 1393bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // property. It's true even if some slots represent deleted properties 1403bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // (their names are the null value). 1413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch for (int i = 0; i < kProbes; i++) { 1423bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // r0 points to properties hash. 1433bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 1443bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register index = r1; 1453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Capacity is smi 2^n. 1463bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset)); 1473bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ decl(index); 1483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ and_(index, 1493bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Immediate(name->Hash() + StringDictionary::GetProbeOffset(i))); 1503bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1513bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Scale the index by multiplying by the entry size. 1523bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 1533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. 1543bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1553bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register entity_name = r1; 1563bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Having undefined at this place means the name is not contained. 1573bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch ASSERT_EQ(kSmiTagSize, 1); 1583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(entity_name, Operand(properties, index, times_pointer_size, 1593bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch kElementsStartOffset - kHeapObjectTag)); 1603bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ Cmp(entity_name, Factory::undefined_value()); 1613bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // __ jmp(miss_label); 1623bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (i != kProbes - 1) { 1633bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(equal, &done); 1643bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1653bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Stop if found the property. 1663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ Cmp(entity_name, Handle<String>(name)); 1673bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(equal, miss_label); 1683bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1693bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Check if the entry name is not a symbol. 1703bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); 1713bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset), 1723bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Immediate(kIsSymbolMask)); 1733bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(zero, miss_label); 1743bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } else { 1753bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Give up probing if still not found the undefined value. 1763bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(not_equal, miss_label); 1773bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 1783bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 1793bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1803bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ bind(&done); 1813bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ DecrementCounter(&Counters::negative_lookups_miss, 1); 1823bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch} 1833bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1843bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { 186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); 187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Code* code = NULL; 188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (kind == Code::LOAD_IC) { 189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block code = Builtins::builtin(Builtins::LoadIC_Miss); 190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block code = Builtins::builtin(Builtins::KeyedLoadIC_Miss); 192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Code> ic(code); 195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Jump(ic, RelocInfo::CODE_TARGET); 196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, 200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int index, 201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register prototype) { 202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the global or builtins object from the current context. 203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(prototype, 204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); 205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the global context from the global or builtins object. 206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(prototype, 207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FieldOperand(prototype, GlobalObject::kGlobalContextOffset)); 208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the function from the global context. 209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(prototype, Operand(prototype, Context::SlotOffset(index))); 210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the initial map. The global functions all have initial maps. 211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(prototype, 212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset)); 213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the prototype from the initial map. 214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); 215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2187f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( 2190d5e116f6aee03185f237311a943491bb079a768Kristian Monsen MacroAssembler* masm, int index, Register prototype, Label* miss) { 2200d5e116f6aee03185f237311a943491bb079a768Kristian Monsen // Check we're still in the same context. 2210d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ Move(prototype, Top::global()); 2220d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)), 2230d5e116f6aee03185f237311a943491bb079a768Kristian Monsen prototype); 2240d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ j(not_equal, miss); 2257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Get the global function with the given index. 2267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch JSFunction* function = JSFunction::cast(Top::global_context()->get(index)); 2277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Load its initial map. The global functions all have initial maps. 2287f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ Move(prototype, Handle<Map>(function->initial_map())); 2297f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Load the prototype from the initial map. 2307f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); 2317f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch} 2327f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 2337f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Load a fast property out of a holder object (src). In-object properties 235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// are loaded directly otherwise the property is loaded from the properties 236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// fixed array. 237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, 238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register dst, Register src, 239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, int index) { 240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Adjust for the number of properties stored in the holder. 241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index -= holder->map()->inobject_properties(); 242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (index < 0) { 243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the property straight out of the holder. 244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int offset = holder->map()->instance_size() + (index * kPointerSize); 245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(dst, FieldOperand(src, offset)); 246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Calculate the offset into the properties array. 248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int offset = index * kPointerSize + FixedArray::kHeaderSize; 249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset)); 250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(dst, FieldOperand(dst, offset)); 251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void PushInterceptorArguments(MacroAssembler* masm, 256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register holder, 258402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Register name, 259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder_obj) { 260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(name); 261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor(); 2624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke ASSERT(!Heap::InNewSpace(interceptor)); 2636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ Move(kScratchRegister, Handle<Object>(interceptor)); 264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(kScratchRegister); 2656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ push(receiver); 2666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ push(holder); 267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset)); 268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCache::GenerateProbe(MacroAssembler* masm, 272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Code::Flags flags, 273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register name, 275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch, 276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register extra) { 277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block USE(extra); // The register extra is not used on the X64 platform. 279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Make sure that code is valid. The shifting code relies on the 280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // entry size being 16. 281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(sizeof(Entry) == 16); 282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Make sure the flags do not name a specific type. 284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(Code::ExtractTypeFromFlags(flags) == 0); 285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Make sure that there are no register conflicts. 287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!scratch.is(receiver)); 288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!scratch.is(name)); 289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the receiver isn't a smi. 291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(receiver, &miss); 292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the map of the receiver and compute the hash. 294d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movl(scratch, FieldOperand(name, String::kHashFieldOffset)); 295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Use only the low 32 bits of the map pointer. 296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); 297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ xor_(scratch, Immediate(flags)); 298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize)); 299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Probe the primary table. 301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ProbeTable(masm, flags, kPrimary, name, scratch); 302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Primary miss: Compute hash for secondary probe. 304d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movl(scratch, FieldOperand(name, String::kHashFieldOffset)); 305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); 306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ xor_(scratch, Immediate(flags)); 307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize)); 308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ subl(scratch, name); 309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ addl(scratch, Immediate(flags)); 310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ and_(scratch, Immediate((kSecondaryTableSize - 1) << kHeapObjectTagSize)); 311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Probe the secondary table. 313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ProbeTable(masm, flags, kSecondary, name, scratch); 314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Cache miss: Fall-through and let caller handle the miss by 316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // entering the runtime system. 317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 321402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu// Both name_reg and receiver_reg are preserved on jumps to miss_label, 322402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu// but may be destroyed if store is successful. 323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateStoreField(MacroAssembler* masm, 324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* object, 325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int index, 326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Map* transition, 327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver_reg, 328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register name_reg, 329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch, 330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* miss_label) { 331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the object isn't a smi. 332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(receiver_reg, miss_label); 333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the map of the object hasn't changed. 335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset), 336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Map>(object->map())); 337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, miss_label); 338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Perform global security token check if needed. 340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (object->IsJSGlobalProxy()) { 341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label); 342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Stub never generated for non-global objects that require access 345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // checks. 346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); 347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Perform map transition for the receiver if necessary. 349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) { 350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The properties must be extended before we can store the value. 351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We jump to a runtime call that extends the properties array. 352402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ pop(scratch); // Return address. 353402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ push(receiver_reg); 354402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ Push(Handle<Map>(transition)); 355402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ push(rax); 356402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ push(scratch); 3576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ TailCallExternalReference( 358402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)), 3, 1); 359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (transition != NULL) { 363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Update the map of the object; no write barrier updating is 364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // needed because the map is never in new space. 365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset), 366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Map>(transition)); 367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Adjust for the number of properties stored in the object. Even in the 370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // face of a transition we can use the old map here because the size of the 371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // object and the number of in-object properties is not going to change. 372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index -= object->map()->inobject_properties(); 373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (index < 0) { 375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Set the property straight into the object. 376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int offset = object->map()->instance_size() + (index * kPointerSize); 377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(FieldOperand(receiver_reg, offset), rax); 378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Update the write barrier for the array address. 380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Pass the value being stored in the now unused name_reg. 381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(name_reg, rax); 382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ RecordWrite(receiver_reg, offset, name_reg, scratch); 383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Write to the properties array. 385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int offset = index * kPointerSize + FixedArray::kHeaderSize; 386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the properties array (optimistically). 387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); 388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(FieldOperand(scratch, offset), rax); 389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Update the write barrier for the array address. 391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Pass the value being stored in the now unused name_reg. 392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(name_reg, rax); 393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ RecordWrite(scratch, offset, name_reg, receiver_reg); 394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the value (register rax). 397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, 402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch, 404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* miss_label) { 405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the receiver isn't a smi. 406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(receiver, miss_label); 407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the object is a JS array. 409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); 410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, miss_label); 411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load length directly from the JS array. 413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, FieldOperand(receiver, JSArray::kLengthOffset)); 414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Generate code to check if an object is a string. If the object is 419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// a string, the map's instance type is left in the scratch register. 420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void GenerateStringCheck(MacroAssembler* masm, 421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch, 423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* smi, 424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* non_string_object) { 425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the object isn't a smi. 426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(receiver, smi); 427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the object is a string. 429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); 430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movzxbq(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); 431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(kNotStringTag != 0); 432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ testl(scratch, Immediate(kNotStringTag)); 433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_zero, non_string_object); 434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, 438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 439402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Register scratch1, 440402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Register scratch2, 441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* miss) { 442402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Label check_wrapper; 443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the object is a string leaving the instance type in the 445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // scratch register. 446402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper); 447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load length directly from the string. 4496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rax, FieldOperand(receiver, String::kLengthOffset)); 450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the object is a JSValue wrapper. 453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&check_wrapper); 454402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ cmpl(scratch1, Immediate(JS_VALUE_TYPE)); 455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, miss); 456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the wrapped value is a string and load the length 458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // directly if it is. 459402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); 460402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu GenerateStringCheck(masm, scratch2, scratch1, miss, miss); 4616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rax, FieldOperand(scratch2, String::kLengthOffset)); 462402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ ret(0); 463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm, 467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register holder, 469402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Register name, 470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder_obj) { 471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block PushInterceptorArguments(masm, receiver, holder, name, holder_obj); 472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference ref = 474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly)); 475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, Immediate(5)); 476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbx, ref); 477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CEntryStub stub(1); 479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CallStub(&stub); 480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, 485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register result, 487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch, 488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* miss_label) { 489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ TryGetFunctionPrototype(receiver, result, miss_label); 490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!result.is(rax)) __ movq(rax, result); 491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// Reserves space for the extra arguments to FastHandleApiCall in the 4966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// caller's frame. 4976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// 4986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// These arguments are set by CheckPrototypes and GenerateFastApiCall. 4996ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockstatic void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { 5006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------- S t a t e ------------- 5016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[0] : return address 5026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[8] : last argument in the internal frame of the caller 5036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------------------------------- 5046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(scratch, Operand(rsp, 0)); 5056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ subq(rsp, Immediate(4 * kPointerSize)); 5066ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(Operand(rsp, 0), scratch); 5076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ Move(scratch, Smi::FromInt(0)); 5086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(Operand(rsp, 1 * kPointerSize), scratch); 5096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(Operand(rsp, 2 * kPointerSize), scratch); 5106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(Operand(rsp, 3 * kPointerSize), scratch); 5116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(Operand(rsp, 4 * kPointerSize), scratch); 5126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 5136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// Undoes the effects of ReserveSpaceForFastApiCall. 5166ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockstatic void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { 5176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------- S t a t e ------------- 5186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[0] : return address 5196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[8] : last fast api call extra argument 5206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- ... 5216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[32] : first fast api call extra argument 5226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[40] : last argument in the internal frame 5236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------------------------------- 5246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(scratch, Operand(rsp, 0)); 5256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(Operand(rsp, 4 * kPointerSize), scratch); 5266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ addq(rsp, Immediate(kPointerSize * 4)); 5276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 5286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// Generates call to FastHandleApiCall builtin. 5316ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockstatic void GenerateFastApiCall(MacroAssembler* masm, 5326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block const CallOptimization& optimization, 5336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block int argc) { 5346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------- S t a t e ------------- 5356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[0] : return address 5366ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[8] : object passing the type check 5376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // (last fast api call extra argument, 5386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // set by CheckPrototypes) 5396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[16] : api call data 5406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[24] : api callback 5416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[32] : api function 5426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // (first fast api call extra argument) 5436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[40] : last argument 5446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- ... 5456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[(argc + 5) * 8] : first argument 5466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[(argc + 6) * 8] : receiver 5476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------------------------------- 5486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Get the function and setup the context. 5506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSFunction* function = optimization.constant_function(); 5516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ Move(rdi, Handle<JSFunction>(function)); 5526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); 5536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Pass the additional arguments FastHandleApiCall expects. 5556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(Operand(rsp, 4 * kPointerSize), rdi); 5566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block bool info_loaded = false; 5576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Object* callback = optimization.api_call_info()->callback(); 5586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (Heap::InNewSpace(callback)) { 5596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block info_loaded = true; 5606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ Move(rcx, Handle<CallHandlerInfo>(optimization.api_call_info())); 5616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kCallbackOffset)); 5626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(Operand(rsp, 3 * kPointerSize), rbx); 5636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } else { 5646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ Move(Operand(rsp, 3 * kPointerSize), Handle<Object>(callback)); 5656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 5666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Object* call_data = optimization.api_call_info()->data(); 5676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (Heap::InNewSpace(call_data)) { 5686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (!info_loaded) { 5696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ Move(rcx, Handle<CallHandlerInfo>(optimization.api_call_info())); 5706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 5716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset)); 5726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(Operand(rsp, 2 * kPointerSize), rbx); 5736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } else { 5746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ Move(Operand(rsp, 2 * kPointerSize), Handle<Object>(call_data)); 5756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 5766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Set the number of arguments. 5786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rax, Immediate(argc + 4)); 5796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Jump to the fast api call builtin (tail call). 5816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Handle<Code> code = Handle<Code>( 5826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Builtins::builtin(Builtins::FastHandleApiCall)); 5836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ParameterCount expected(0); 5846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ InvokeCode(code, expected, expected, 5856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block RelocInfo::CODE_TARGET, JUMP_FUNCTION); 5866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 5876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass CallInterceptorCompiler BASE_EMBEDDED { 590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 5916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CallInterceptorCompiler(StubCompiler* stub_compiler, 5926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block const ParameterCount& arguments, 5936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register name) 5946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block : stub_compiler_(stub_compiler), 5956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block arguments_(arguments), 5966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block name_(name) {} 5976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block void Compile(MacroAssembler* masm, 5996ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSObject* object, 6006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSObject* holder, 6016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block String* name, 6026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block LookupResult* lookup, 6036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register receiver, 6046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register scratch1, 6056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register scratch2, 6063bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register scratch3, 6076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label* miss) { 6086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ASSERT(holder->HasNamedInterceptor()); 6096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); 6106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 6116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Check that the receiver isn't a smi. 6126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ JumpIfSmi(receiver, miss); 6136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 6146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CallOptimization optimization(lookup); 6156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 6166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (optimization.is_constant_call()) { 6176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CompileCacheable(masm, 6186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block object, 6196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block receiver, 6206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block scratch1, 6216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block scratch2, 6223bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch3, 6236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block holder, 6246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block lookup, 6256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block name, 6266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block optimization, 6276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block miss); 6286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } else { 6296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CompileRegular(masm, 6306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block object, 6316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block receiver, 6326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block scratch1, 6336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block scratch2, 6343bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch3, 6356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block name, 6366ded16be15dd865a9b21ea304d5273c8be299c87Steve Block holder, 6376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block miss); 6386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 6396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block private: 642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block void CompileCacheable(MacroAssembler* masm, 6436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSObject* object, 644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch1, 646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch2, 6473bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register scratch3, 648f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke JSObject* interceptor_holder, 649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LookupResult* lookup, 650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name, 6516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block const CallOptimization& optimization, 652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* miss_label) { 6536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ASSERT(optimization.is_constant_call()); 6546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ASSERT(!lookup->holder()->IsGlobalObject()); 6556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 6566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block int depth1 = kInvalidProtoDepth; 6576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block int depth2 = kInvalidProtoDepth; 6586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block bool can_do_fast_api_call = false; 6596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (optimization.is_simple_api_call() && 6606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block !lookup->holder()->IsGlobalObject()) { 661f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke depth1 = 662f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke optimization.GetPrototypeDepthOfExpectedType(object, 663f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke interceptor_holder); 6646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (depth1 == kInvalidProtoDepth) { 665f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke depth2 = 666f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke optimization.GetPrototypeDepthOfExpectedType(interceptor_holder, 667f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke lookup->holder()); 668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || 6706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block (depth2 != kInvalidProtoDepth); 671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ IncrementCounter(&Counters::call_const_interceptor, 1); 674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (can_do_fast_api_call) { 6766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1); 6776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ReserveSpaceForFastApiCall(masm, scratch1); 6786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 679402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 680f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // Check that the maps from receiver to interceptor's holder 681f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // haven't changed and thus we can invoke interceptor. 6826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label miss_cleanup; 6836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; 6846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register holder = 6857f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch stub_compiler_->CheckPrototypes(object, receiver, 6867f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch interceptor_holder, scratch1, 6873bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch2, scratch3, name, depth1, miss); 688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 689f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // Invoke an interceptor and if it provides a value, 690f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // branch to |regular_invoke|. 6916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label regular_invoke; 692f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke LoadWithInterceptor(masm, receiver, holder, interceptor_holder, 693f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke ®ular_invoke); 694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 695f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // Interceptor returned nothing for this property. Try to use cached 696f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // constant function. 697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 698f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // Check that the maps from interceptor's holder to constant function's 699f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // holder haven't changed and thus we can use cached constant function. 7007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch if (interceptor_holder != lookup->holder()) { 7017f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch stub_compiler_->CheckPrototypes(interceptor_holder, receiver, 7027f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch lookup->holder(), scratch1, 7033bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch2, scratch3, name, depth2, miss); 7047f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } else { 7057f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // CheckPrototypes has a side effect of fetching a 'holder' 7067f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // for API (object which is instanceof for the signature). It's 7077f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // safe to omit it here, as if present, it should be fetched 7087f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // by the previous CheckPrototypes. 7097f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch ASSERT(depth2 == kInvalidProtoDepth); 7107f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } 711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 712f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // Invoke function. 7136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (can_do_fast_api_call) { 7146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block GenerateFastApiCall(masm, optimization, arguments_.immediate()); 7156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } else { 7166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ InvokeFunction(optimization.constant_function(), arguments_, 7176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JUMP_FUNCTION); 7186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 720f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // Deferred code for fast API call case---clean preallocated space. 7216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (can_do_fast_api_call) { 7226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ bind(&miss_cleanup); 7236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block FreeSpaceForFastApiCall(masm, scratch1); 7246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ jmp(miss_label); 7256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 727f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // Invoke a regular function. 7286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ bind(®ular_invoke); 7296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (can_do_fast_api_call) { 7306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block FreeSpaceForFastApiCall(masm, scratch1); 7316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block void CompileRegular(MacroAssembler* masm, 7356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSObject* object, 736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 7376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register scratch1, 7386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register scratch2, 7393bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register scratch3, 7406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block String* name, 741f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke JSObject* interceptor_holder, 742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* miss_label) { 7436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register holder = 744f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, 7453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch1, scratch2, scratch3, name, 7466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block miss_label); 7476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ EnterInternalFrame(); 749402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Save the name_ register across the call. 750402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ push(name_); 751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block PushInterceptorArguments(masm, 753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block receiver, 754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block holder, 755402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu name_, 756f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke interceptor_holder); 757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 758402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ CallExternalReference( 759402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall)), 760402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 5); 761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Restore the name_ register. 763402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ pop(name_); 764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ LeaveInternalFrame(); 765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block void LoadWithInterceptor(MacroAssembler* masm, 7686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register receiver, 7696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register holder, 7706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSObject* holder_obj, 7716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label* interceptor_succeeded) { 7726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ EnterInternalFrame(); 7736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ push(holder); // Save the holder. 7746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ push(name_); // Save the name. 7756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 7766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CompileCallLoadPropertyWithInterceptor(masm, 7776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block receiver, 7786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block holder, 7796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block name_, 7806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block holder_obj); 7816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 7826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ pop(name_); // Restore the name. 7836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ pop(receiver); // Restore the holder. 7846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ LeaveInternalFrame(); 7856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 7866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); 7876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ j(not_equal, interceptor_succeeded); 7886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 7896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 7906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block StubCompiler* stub_compiler_; 791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const ParameterCount& arguments_; 792402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Register name_; 793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// Generate code to check that a global property cell is empty. Create 7976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// the property cell at compilation time if no cell exists for the 7986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// property. 7996ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockstatic Object* GenerateCheckPropertyCell(MacroAssembler* masm, 8006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block GlobalObject* global, 8016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block String* name, 8026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register scratch, 8036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label* miss) { 8046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Object* probe = global->EnsurePropertyCell(name); 8056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (probe->IsFailure()) return probe; 8066ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); 8076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ASSERT(cell->value()->IsTheHole()); 8086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ Move(scratch, Handle<Object>(cell)); 8096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), 8106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Factory::the_hole_value()); 8116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ j(not_equal, miss); 8126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block return cell; 8136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 8146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 8156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __ 817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM((masm())) 819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8209dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 8219dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenvoid CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { 8229dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen if (kind_ == Code::KEYED_CALL_IC) { 8239dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen __ Cmp(rcx, Handle<String>(name)); 8249dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen __ j(not_equal, miss); 8259dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen } 8269dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen} 8279dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 8289dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 82959151504615d929945dc59db37bf1166937748c6Steve Blockvoid CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object, 83059151504615d929945dc59db37bf1166937748c6Steve Block JSObject* holder, 83159151504615d929945dc59db37bf1166937748c6Steve Block String* name, 83259151504615d929945dc59db37bf1166937748c6Steve Block Label* miss) { 83359151504615d929945dc59db37bf1166937748c6Steve Block ASSERT(holder->IsGlobalObject()); 83459151504615d929945dc59db37bf1166937748c6Steve Block 83559151504615d929945dc59db37bf1166937748c6Steve Block // Get the number of arguments. 83659151504615d929945dc59db37bf1166937748c6Steve Block const int argc = arguments().immediate(); 83759151504615d929945dc59db37bf1166937748c6Steve Block 83859151504615d929945dc59db37bf1166937748c6Steve Block // Get the receiver from the stack. 83959151504615d929945dc59db37bf1166937748c6Steve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 84059151504615d929945dc59db37bf1166937748c6Steve Block 84159151504615d929945dc59db37bf1166937748c6Steve Block // If the object is the holder then we know that it's a global 84259151504615d929945dc59db37bf1166937748c6Steve Block // object which can only happen for contextual calls. In this case, 84359151504615d929945dc59db37bf1166937748c6Steve Block // the receiver cannot be a smi. 84459151504615d929945dc59db37bf1166937748c6Steve Block if (object != holder) { 84559151504615d929945dc59db37bf1166937748c6Steve Block __ JumpIfSmi(rdx, miss); 84659151504615d929945dc59db37bf1166937748c6Steve Block } 84759151504615d929945dc59db37bf1166937748c6Steve Block 84859151504615d929945dc59db37bf1166937748c6Steve Block // Check that the maps haven't changed. 84959151504615d929945dc59db37bf1166937748c6Steve Block CheckPrototypes(object, rdx, holder, rbx, rax, rdi, name, miss); 85059151504615d929945dc59db37bf1166937748c6Steve Block} 85159151504615d929945dc59db37bf1166937748c6Steve Block 85259151504615d929945dc59db37bf1166937748c6Steve Block 85359151504615d929945dc59db37bf1166937748c6Steve Blockvoid CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, 85459151504615d929945dc59db37bf1166937748c6Steve Block JSFunction* function, 85559151504615d929945dc59db37bf1166937748c6Steve Block Label* miss) { 85659151504615d929945dc59db37bf1166937748c6Steve Block // Get the value from the cell. 85759151504615d929945dc59db37bf1166937748c6Steve Block __ Move(rdi, Handle<JSGlobalPropertyCell>(cell)); 85859151504615d929945dc59db37bf1166937748c6Steve Block __ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset)); 85959151504615d929945dc59db37bf1166937748c6Steve Block 86059151504615d929945dc59db37bf1166937748c6Steve Block // Check that the cell contains the same function. 86159151504615d929945dc59db37bf1166937748c6Steve Block if (Heap::InNewSpace(function)) { 86259151504615d929945dc59db37bf1166937748c6Steve Block // We can't embed a pointer to a function in new space so we have 86359151504615d929945dc59db37bf1166937748c6Steve Block // to verify that the shared function info is unchanged. This has 86459151504615d929945dc59db37bf1166937748c6Steve Block // the nice side effect that multiple closures based on the same 86559151504615d929945dc59db37bf1166937748c6Steve Block // function can all use this call IC. Before we load through the 86659151504615d929945dc59db37bf1166937748c6Steve Block // function, we have to verify that it still is a function. 86759151504615d929945dc59db37bf1166937748c6Steve Block __ JumpIfSmi(rdi, miss); 86859151504615d929945dc59db37bf1166937748c6Steve Block __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax); 86959151504615d929945dc59db37bf1166937748c6Steve Block __ j(not_equal, miss); 87059151504615d929945dc59db37bf1166937748c6Steve Block 87159151504615d929945dc59db37bf1166937748c6Steve Block // Check the shared function info. Make sure it hasn't changed. 87259151504615d929945dc59db37bf1166937748c6Steve Block __ Move(rax, Handle<SharedFunctionInfo>(function->shared())); 87359151504615d929945dc59db37bf1166937748c6Steve Block __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax); 87459151504615d929945dc59db37bf1166937748c6Steve Block __ j(not_equal, miss); 87559151504615d929945dc59db37bf1166937748c6Steve Block } else { 87659151504615d929945dc59db37bf1166937748c6Steve Block __ Cmp(rdi, Handle<JSFunction>(function)); 87759151504615d929945dc59db37bf1166937748c6Steve Block __ j(not_equal, miss); 87859151504615d929945dc59db37bf1166937748c6Steve Block } 87959151504615d929945dc59db37bf1166937748c6Steve Block} 88059151504615d929945dc59db37bf1166937748c6Steve Block 88159151504615d929945dc59db37bf1166937748c6Steve Block 882bb769b257e753aafcbd96767abb2abc645eaa20cBen MurdochObject* CallStubCompiler::GenerateMissBranch() { 883bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_); 884bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch if (obj->IsFailure()) return obj; 885bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); 886bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch return obj; 8877f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch} 8887f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 8897f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* CallStubCompiler::CompileCallConstant(Object* object, 891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSFunction* function, 893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name, 894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block StubCompiler::CheckType check) { 895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 896402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rcx : function name 897402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[0] : return address 898402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[8] : argument argc 899402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[16] : argument argc - 1 900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ... 901402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[argc * 8] : argument 1 902402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[(argc + 1) * 8] : argument 0 = receiver 903402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // ----------------------------------- 904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 9056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block SharedFunctionInfo* function_info = function->shared(); 9066ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (function_info->HasCustomCallGenerator()) { 90725f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen const int id = function_info->custom_call_generator_id(); 90859151504615d929945dc59db37bf1166937748c6Steve Block Object* result = CompileCustomCall( 90959151504615d929945dc59db37bf1166937748c6Steve Block id, object, holder, NULL, function, name); 9106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // undefined means bail out to regular compiler. 91159151504615d929945dc59db37bf1166937748c6Steve Block if (!result->IsUndefined()) return result; 9126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 9136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 9146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label miss_in_smi_check; 915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 9169dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen GenerateNameCheck(name, &miss_in_smi_check); 9179dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the receiver from the stack. 919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const int argc = arguments().immediate(); 920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the receiver isn't a smi. 923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (check != NUMBER_CHECK) { 9246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ JumpIfSmi(rdx, &miss_in_smi_check); 925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Make sure that it's okay not to patch the on stack receiver 928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // unless we're doing a receiver map check. 929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); 930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 9316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CallOptimization optimization(function); 9326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block int depth = kInvalidProtoDepth; 9336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label miss; 9346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block switch (check) { 936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case RECEIVER_MAP_CHECK: 9376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ IncrementCounter(&Counters::call_const, 1); 9386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 9396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (optimization.is_simple_api_call() && !object->IsGlobalObject()) { 9406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block depth = optimization.GetPrototypeDepthOfExpectedType( 9416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSObject::cast(object), holder); 9426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 9436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 9446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (depth != kInvalidProtoDepth) { 9456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ IncrementCounter(&Counters::call_const_fast_api, 1); 9466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ReserveSpaceForFastApiCall(masm(), rax); 9476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 9486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the maps haven't changed. 950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CheckPrototypes(JSObject::cast(object), rdx, holder, 9513bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch rbx, rax, rdi, name, depth, &miss); 952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Patch the receiver on the stack with the global proxy if 954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // necessary. 955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (object->IsGlobalObject()) { 9566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ASSERT(depth == kInvalidProtoDepth); 957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); 958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); 959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case STRING_CHECK: 963e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (!function->IsBuiltin()) { 964e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Calling non-builtins with a value as receiver requires boxing. 965e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ jmp(&miss); 966e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 967e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Check that the object is a two-byte string or a symbol. 968402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax); 969e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(above_equal, &miss); 970e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Check that the maps starting from the prototype haven't changed. 9717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch GenerateDirectLoadGlobalFunctionPrototype( 9720d5e116f6aee03185f237311a943491bb079a768Kristian Monsen masm(), Context::STRING_FUNCTION_INDEX, rax, &miss); 973402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 9743bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch rbx, rdx, rdi, name, &miss); 975e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case NUMBER_CHECK: { 979e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (!function->IsBuiltin()) { 980e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Calling non-builtins with a value as receiver requires boxing. 981e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ jmp(&miss); 982e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 983e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label fast; 984e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Check that the object is a smi or a heap number. 985e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ JumpIfSmi(rdx, &fast); 986402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax); 987e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(not_equal, &miss); 988e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&fast); 989e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Check that the maps starting from the prototype haven't changed. 9907f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch GenerateDirectLoadGlobalFunctionPrototype( 9910d5e116f6aee03185f237311a943491bb079a768Kristian Monsen masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss); 992402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 9933bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch rbx, rdx, rdi, name, &miss); 994e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block case BOOLEAN_CHECK: { 999e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke if (!function->IsBuiltin()) { 1000e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Calling non-builtins with a value as receiver requires boxing. 1001e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ jmp(&miss); 1002e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } else { 1003e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label fast; 1004e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Check that the object is a boolean. 1005e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ CompareRoot(rdx, Heap::kTrueValueRootIndex); 1006e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(equal, &fast); 1007e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ CompareRoot(rdx, Heap::kFalseValueRootIndex); 1008e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ j(not_equal, &miss); 1009e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ bind(&fast); 1010e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Check that the maps starting from the prototype haven't changed. 10117f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch GenerateDirectLoadGlobalFunctionPrototype( 10120d5e116f6aee03185f237311a943491bb079a768Kristian Monsen masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss); 1013402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 10143bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch rbx, rdx, rdi, name, &miss); 1015e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 1016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 1017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block default: 1020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UNREACHABLE(); 1021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 10236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (depth != kInvalidProtoDepth) { 10246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block GenerateFastApiCall(masm(), optimization, argc); 10256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } else { 10266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ InvokeFunction(function, arguments(), JUMP_FUNCTION); 10276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 1028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle call cache miss. 1030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 10316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (depth != kInvalidProtoDepth) { 10326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block FreeSpaceForFastApiCall(masm(), rax); 10336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 10346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 10356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Handle call cache miss. 10366ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ bind(&miss_in_smi_check); 1037bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Object* obj = GenerateMissBranch(); 1038bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch if (obj->IsFailure()) return obj; 1039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 104125f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen return GetCode(function); 1042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1045402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei PopescuObject* CallStubCompiler::CompileCallField(JSObject* object, 1046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 1047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int index, 1048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name) { 1049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 1050402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rcx : function name 1051402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[0] : return address 1052402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[8] : argument argc 1053402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[16] : argument argc - 1 1054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ... 1055402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[argc * 8] : argument 1 1056402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[(argc + 1) * 8] : argument 0 = receiver 1057402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // ----------------------------------- 1058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 1059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 10609dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen GenerateNameCheck(name, &miss); 10619dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 1062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the receiver from the stack. 1063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const int argc = arguments().immediate(); 1064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 1065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the receiver isn't a smi. 1067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(rdx, &miss); 1068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Do the right check and compute the holder register. 10703bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register reg = CheckPrototypes(object, rdx, holder, rbx, rax, rdi, 10713bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch name, &miss); 1072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateFastPropertyLoad(masm(), rdi, reg, holder, index); 1074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the function really is a function. 1076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(rdi, &miss); 1077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rbx); 1078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 1079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Patch the receiver on the stack with the global proxy if 1081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // necessary. 1082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (object->IsGlobalObject()) { 1083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); 1084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); 1085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Invoke the function. 1088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION); 1089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle call cache miss. 1091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 1092bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Object* obj = GenerateMissBranch(); 1093bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch if (obj->IsFailure()) return obj; 1094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 1096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(FIELD, name); 1097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 11006ded16be15dd865a9b21ea304d5273c8be299c87Steve BlockObject* CallStubCompiler::CompileArrayPushCall(Object* object, 11016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSObject* holder, 110259151504615d929945dc59db37bf1166937748c6Steve Block JSGlobalPropertyCell* cell, 11036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSFunction* function, 110459151504615d929945dc59db37bf1166937748c6Steve Block String* name) { 11056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------- S t a t e ------------- 11066ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rcx : name 11076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[0] : return address 11086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[(argc - n) * 8] : arg[n] (zero-based) 11096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- ... 11106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[(argc + 1) * 8] : receiver 11116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------------------------------- 11126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // If object is not an array, bail out to regular call. 111459151504615d929945dc59db37bf1166937748c6Steve Block if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value(); 11156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label miss; 11176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11189dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen GenerateNameCheck(name, &miss); 11199dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 11206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Get the receiver from the stack. 11216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block const int argc = arguments().immediate(); 11226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 11236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Check that the receiver isn't a smi. 11256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ JumpIfSmi(rdx, &miss); 11266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CheckPrototypes(JSObject::cast(object), 11286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block rdx, 11296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block holder, 11306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block rbx, 11316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block rax, 11323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch rdi, 11336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block name, 11346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block &miss); 11356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11366ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (argc == 0) { 11376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Noop, return the length. 11386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset)); 11396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ ret((argc + 1) * kPointerSize); 11406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } else { 1141756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick Label call_builtin; 1142756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick 11436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Get the elements array of the object. 11446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset)); 11456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 1146756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick // Check that the elements are in fast mode and writable. 11476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), 11486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Factory::fixed_array_map()); 1149756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick __ j(not_equal, &call_builtin); 11506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (argc == 1) { // Otherwise fall through to call builtin. 1152756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick Label exit, with_write_barrier, attempt_to_grow_elements; 11536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Get the array's length into rax and calculate new length. 11559dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset)); 11566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue); 11579dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen __ addl(rax, Immediate(argc)); 11586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Get the element's length into rcx. 11609dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen __ SmiToInteger32(rcx, FieldOperand(rbx, FixedArray::kLengthOffset)); 11616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Check if we could survive without allocation. 11639dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen __ cmpl(rax, rcx); 11646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ j(greater, &attempt_to_grow_elements); 11656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Save new length. 11679dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax); 11686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Push the element. 11706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rcx, Operand(rsp, argc * kPointerSize)); 11716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ lea(rdx, FieldOperand(rbx, 11729dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen rax, times_pointer_size, 11736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block FixedArray::kHeaderSize - argc * kPointerSize)); 11746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(Operand(rdx, 0), rcx); 11756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Check if value is a smi. 11779dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen __ Integer32ToSmi(rax, rax); // Return new length as smi. 11789dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 11797f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ JumpIfNotSmi(rcx, &with_write_barrier); 11806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ bind(&exit); 11826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ ret((argc + 1) * kPointerSize); 11836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11847f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ bind(&with_write_barrier); 11856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ InNewSpace(rbx, rcx, equal, &exit); 11876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block RecordWriteStub stub(rbx, rdx, rcx); 11896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ CallStub(&stub); 11909dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 11916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ ret((argc + 1) * kPointerSize); 11926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ bind(&attempt_to_grow_elements); 11946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ExternalReference new_space_allocation_top = 11956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ExternalReference::new_space_allocation_top_address(); 11966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ExternalReference new_space_allocation_limit = 11976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ExternalReference::new_space_allocation_limit_address(); 11986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11996ded16be15dd865a9b21ea304d5273c8be299c87Steve Block const int kAllocationDelta = 4; 12006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Load top. 12016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rcx, new_space_allocation_top); 12026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rcx, Operand(rcx, 0)); 12036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Check if it's the end of elements. 12056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ lea(rdx, FieldOperand(rbx, 12069dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen rax, times_pointer_size, 12076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block FixedArray::kHeaderSize - argc * kPointerSize)); 12086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ cmpq(rdx, rcx); 12096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ j(not_equal, &call_builtin); 12106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ addq(rcx, Immediate(kAllocationDelta * kPointerSize)); 12116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(kScratchRegister, new_space_allocation_limit); 12126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ cmpq(rcx, Operand(kScratchRegister, 0)); 12136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ j(above, &call_builtin); 12146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // We fit and could grow elements. 12166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(kScratchRegister, new_space_allocation_top); 12176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(Operand(kScratchRegister, 0), rcx); 12186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rcx, Operand(rsp, argc * kPointerSize)); 12196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Push the argument... 12216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(Operand(rdx, 0), rcx); 12226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ... and fill the rest with holes. 1223756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); 12246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block for (int i = 1; i < kAllocationDelta; i++) { 12256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(Operand(rdx, i * kPointerSize), kScratchRegister); 12266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 12276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Restore receiver to rdx as finish sequence assumes it's here. 12296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 12306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Increment element's and array's sizes. 12327f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ SmiAddConstant(FieldOperand(rbx, FixedArray::kLengthOffset), 12337f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch Smi::FromInt(kAllocationDelta)); 1234756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick 12359dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen // Make new length a smi before returning it. 12369dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen __ Integer32ToSmi(rax, rax); 12376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax); 1238756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick 12397f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Elements are in new space, so write barrier is not required. 12406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ ret((argc + 1) * kPointerSize); 12416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 12426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 1243756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick __ bind(&call_builtin); 12446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush), 12456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block argc + 1, 12466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 1); 12476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 12486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ bind(&miss); 1250bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Object* obj = GenerateMissBranch(); 1251bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch if (obj->IsFailure()) return obj; 12526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Return the generated code. 125425f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen return GetCode(function); 12556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 12566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12586ded16be15dd865a9b21ea304d5273c8be299c87Steve BlockObject* CallStubCompiler::CompileArrayPopCall(Object* object, 12596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSObject* holder, 126059151504615d929945dc59db37bf1166937748c6Steve Block JSGlobalPropertyCell* cell, 12616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSFunction* function, 126259151504615d929945dc59db37bf1166937748c6Steve Block String* name) { 12636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------- S t a t e ------------- 1264756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick // -- rcx : name 1265756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick // -- rsp[0] : return address 1266756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick // -- rsp[(argc - n) * 8] : arg[n] (zero-based) 12676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- ... 1268756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick // -- rsp[(argc + 1) * 8] : receiver 12696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------------------------------- 12706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // If object is not an array, bail out to regular call. 127259151504615d929945dc59db37bf1166937748c6Steve Block if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value(); 12736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label miss, return_undefined, call_builtin; 12756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12769dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen GenerateNameCheck(name, &miss); 12779dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 12786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Get the receiver from the stack. 12796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block const int argc = arguments().immediate(); 12806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 12816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Check that the receiver isn't a smi. 12836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ JumpIfSmi(rdx, &miss); 12846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CheckPrototypes(JSObject::cast(object), rdx, 12866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block holder, rbx, 12873bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch rax, rdi, name, &miss); 12886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Get the elements array of the object. 12906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset)); 12916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 1292756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick // Check that the elements are in fast mode and writable. 1293756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), 1294756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick Heap::kFixedArrayMapRootIndex); 1295756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick __ j(not_equal, &call_builtin); 12966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Get the array's length into rcx and calculate new length. 12989dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen __ SmiToInteger32(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); 12999dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen __ subl(rcx, Immediate(1)); 13006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ j(negative, &return_undefined); 13016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 13026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Get the last element. 1303756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick __ LoadRoot(r9, Heap::kTheHoleValueRootIndex); 13046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rax, FieldOperand(rbx, 13059dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen rcx, times_pointer_size, 13066ded16be15dd865a9b21ea304d5273c8be299c87Steve Block FixedArray::kHeaderSize)); 13076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Check if element is already the hole. 13086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ cmpq(rax, r9); 13099dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen // If so, call slow-case to also check prototypes for value. 13106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ j(equal, &call_builtin); 13116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 13126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Set the array's length. 13139dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rcx); 13146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 13159dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen // Fill with the hole and return original value. 13166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(FieldOperand(rbx, 13179dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen rcx, times_pointer_size, 13186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block FixedArray::kHeaderSize), 13196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block r9); 13206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ ret((argc + 1) * kPointerSize); 13216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 13226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ bind(&return_undefined); 1323756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); 13246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ ret((argc + 1) * kPointerSize); 13256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 13266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ bind(&call_builtin); 13276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop), 13286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block argc + 1, 13296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 1); 1330756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick 13316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ bind(&miss); 1332bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Object* obj = GenerateMissBranch(); 1333bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch if (obj->IsFailure()) return obj; 13346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 13356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Return the generated code. 133625f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen return GetCode(function); 13376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 13386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 13396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 13407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen MurdochObject* CallStubCompiler::CompileStringCharAtCall(Object* object, 13417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch JSObject* holder, 134259151504615d929945dc59db37bf1166937748c6Steve Block JSGlobalPropertyCell* cell, 13437f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch JSFunction* function, 134459151504615d929945dc59db37bf1166937748c6Steve Block String* name) { 134580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ----------- S t a t e ------------- 134680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // -- rcx : function name 134780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // -- rsp[0] : return address 134880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // -- rsp[(argc - n) * 8] : arg[n] (zero-based) 134980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // -- ... 135080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // -- rsp[(argc + 1) * 8] : receiver 135180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ----------------------------------- 135280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 135380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If object is not a string, bail out to regular call. 135459151504615d929945dc59db37bf1166937748c6Steve Block if (!object->IsString() || cell != NULL) return Heap::undefined_value(); 135580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 135680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const int argc = arguments().immediate(); 135780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 135880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label miss; 135980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label index_out_of_range; 136080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 136180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateNameCheck(name, &miss); 136280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 136380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the maps starting from the prototype haven't changed. 136480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateDirectLoadGlobalFunctionPrototype(masm(), 136580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Context::STRING_FUNCTION_INDEX, 13660d5e116f6aee03185f237311a943491bb079a768Kristian Monsen rax, 13670d5e116f6aee03185f237311a943491bb079a768Kristian Monsen &miss); 136880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(object != holder); 136980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 137080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen rbx, rdx, rdi, name, &miss); 137180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 137280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register receiver = rax; 137380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register index = rdi; 137480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch1 = rbx; 137580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch2 = rdx; 137680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register result = rax; 137780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); 137880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (argc > 0) { 137980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(index, Operand(rsp, (argc - 0) * kPointerSize)); 138080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 138180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(index, Heap::kUndefinedValueRootIndex); 138280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 138380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 138480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringCharAtGenerator char_at_generator(receiver, 138580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index, 138680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch1, 138780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch2, 138880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen result, 138980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &miss, // When not a string. 139080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &miss, // When not a number. 139180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &index_out_of_range, 139280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STRING_INDEX_IS_NUMBER); 139380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_at_generator.GenerateFast(masm()); 139480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret((argc + 1) * kPointerSize); 139580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 139680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ICRuntimeCallHelper call_helper; 139780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_at_generator.GenerateSlow(masm(), call_helper); 139880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 139980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&index_out_of_range); 140080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(rax, Heap::kEmptyStringRootIndex); 140180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret((argc + 1) * kPointerSize); 140280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 140380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&miss); 140480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Object* obj = GenerateMissBranch(); 140580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (obj->IsFailure()) return obj; 140680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 140780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return the generated code. 140880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return GetCode(function); 14097f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch} 14107f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 14117f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 141259151504615d929945dc59db37bf1166937748c6Steve BlockObject* CallStubCompiler::CompileStringCharCodeAtCall( 141359151504615d929945dc59db37bf1166937748c6Steve Block Object* object, 141459151504615d929945dc59db37bf1166937748c6Steve Block JSObject* holder, 141559151504615d929945dc59db37bf1166937748c6Steve Block JSGlobalPropertyCell* cell, 141659151504615d929945dc59db37bf1166937748c6Steve Block JSFunction* function, 141759151504615d929945dc59db37bf1166937748c6Steve Block String* name) { 141880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ----------- S t a t e ------------- 141980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // -- rcx : function name 142080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // -- rsp[0] : return address 142180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // -- rsp[(argc - n) * 8] : arg[n] (zero-based) 142280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // -- ... 142380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // -- rsp[(argc + 1) * 8] : receiver 142480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ----------------------------------- 142580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 142680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // If object is not a string, bail out to regular call. 142759151504615d929945dc59db37bf1166937748c6Steve Block if (!object->IsString() || cell != NULL) return Heap::undefined_value(); 142880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 142980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen const int argc = arguments().immediate(); 143080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 143180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label miss; 143280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label index_out_of_range; 143380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateNameCheck(name, &miss); 143480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 143580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Check that the maps starting from the prototype haven't changed. 143680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateDirectLoadGlobalFunctionPrototype(masm(), 143780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Context::STRING_FUNCTION_INDEX, 14380d5e116f6aee03185f237311a943491bb079a768Kristian Monsen rax, 14390d5e116f6aee03185f237311a943491bb079a768Kristian Monsen &miss); 144080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ASSERT(object != holder); 144180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 144280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen rbx, rdx, rdi, name, &miss); 144380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 144480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register receiver = rbx; 144580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register index = rdi; 144680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register scratch = rdx; 144780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Register result = rax; 144880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); 144980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (argc > 0) { 145080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ movq(index, Operand(rsp, (argc - 0) * kPointerSize)); 145180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 145280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(index, Heap::kUndefinedValueRootIndex); 145380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 145480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 145580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen StringCharCodeAtGenerator char_code_at_generator(receiver, 145680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen index, 145780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen scratch, 145880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen result, 145980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &miss, // When not a string. 146080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &miss, // When not a number. 146180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen &index_out_of_range, 146280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen STRING_INDEX_IS_NUMBER); 146380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_code_at_generator.GenerateFast(masm()); 146480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret((argc + 1) * kPointerSize); 146580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 146680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen ICRuntimeCallHelper call_helper; 146780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen char_code_at_generator.GenerateSlow(masm(), call_helper); 146880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 146980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&index_out_of_range); 147080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ LoadRoot(rax, Heap::kNanValueRootIndex); 147180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ ret((argc + 1) * kPointerSize); 14727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 147380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&miss); 147480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Object* obj = GenerateMissBranch(); 147580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen if (obj->IsFailure()) return obj; 147680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 147780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return the generated code. 147880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen return GetCode(function); 147980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 14806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 14816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 148259151504615d929945dc59db37bf1166937748c6Steve BlockObject* CallStubCompiler::CompileStringFromCharCodeCall( 148359151504615d929945dc59db37bf1166937748c6Steve Block Object* object, 148459151504615d929945dc59db37bf1166937748c6Steve Block JSObject* holder, 148559151504615d929945dc59db37bf1166937748c6Steve Block JSGlobalPropertyCell* cell, 148659151504615d929945dc59db37bf1166937748c6Steve Block JSFunction* function, 148759151504615d929945dc59db37bf1166937748c6Steve Block String* name) { 148859151504615d929945dc59db37bf1166937748c6Steve Block // ----------- S t a t e ------------- 148959151504615d929945dc59db37bf1166937748c6Steve Block // -- rcx : function name 149059151504615d929945dc59db37bf1166937748c6Steve Block // -- rsp[0] : return address 149159151504615d929945dc59db37bf1166937748c6Steve Block // -- rsp[(argc - n) * 8] : arg[n] (zero-based) 149259151504615d929945dc59db37bf1166937748c6Steve Block // -- ... 149359151504615d929945dc59db37bf1166937748c6Steve Block // -- rsp[(argc + 1) * 8] : receiver 149459151504615d929945dc59db37bf1166937748c6Steve Block // ----------------------------------- 149559151504615d929945dc59db37bf1166937748c6Steve Block 149659151504615d929945dc59db37bf1166937748c6Steve Block const int argc = arguments().immediate(); 149759151504615d929945dc59db37bf1166937748c6Steve Block 149859151504615d929945dc59db37bf1166937748c6Steve Block // If the object is not a JSObject or we got an unexpected number of 149959151504615d929945dc59db37bf1166937748c6Steve Block // arguments, bail out to the regular call. 150059151504615d929945dc59db37bf1166937748c6Steve Block if (!object->IsJSObject() || argc != 1) return Heap::undefined_value(); 150159151504615d929945dc59db37bf1166937748c6Steve Block 150259151504615d929945dc59db37bf1166937748c6Steve Block Label miss; 150359151504615d929945dc59db37bf1166937748c6Steve Block GenerateNameCheck(name, &miss); 150459151504615d929945dc59db37bf1166937748c6Steve Block 150559151504615d929945dc59db37bf1166937748c6Steve Block if (cell == NULL) { 150659151504615d929945dc59db37bf1166937748c6Steve Block __ movq(rdx, Operand(rsp, 2 * kPointerSize)); 150759151504615d929945dc59db37bf1166937748c6Steve Block 150859151504615d929945dc59db37bf1166937748c6Steve Block __ JumpIfSmi(rdx, &miss); 150959151504615d929945dc59db37bf1166937748c6Steve Block 151059151504615d929945dc59db37bf1166937748c6Steve Block CheckPrototypes(JSObject::cast(object), rdx, holder, rbx, rax, rdi, name, 151159151504615d929945dc59db37bf1166937748c6Steve Block &miss); 151259151504615d929945dc59db37bf1166937748c6Steve Block } else { 151359151504615d929945dc59db37bf1166937748c6Steve Block ASSERT(cell->value() == function); 151459151504615d929945dc59db37bf1166937748c6Steve Block GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); 151559151504615d929945dc59db37bf1166937748c6Steve Block GenerateLoadFunctionFromCell(cell, function, &miss); 151659151504615d929945dc59db37bf1166937748c6Steve Block } 151759151504615d929945dc59db37bf1166937748c6Steve Block 151859151504615d929945dc59db37bf1166937748c6Steve Block // Load the char code argument. 151959151504615d929945dc59db37bf1166937748c6Steve Block Register code = rbx; 152059151504615d929945dc59db37bf1166937748c6Steve Block __ movq(code, Operand(rsp, 1 * kPointerSize)); 152159151504615d929945dc59db37bf1166937748c6Steve Block 152259151504615d929945dc59db37bf1166937748c6Steve Block // Check the code is a smi. 152359151504615d929945dc59db37bf1166937748c6Steve Block Label slow; 152459151504615d929945dc59db37bf1166937748c6Steve Block __ JumpIfNotSmi(code, &slow); 152559151504615d929945dc59db37bf1166937748c6Steve Block 152659151504615d929945dc59db37bf1166937748c6Steve Block // Convert the smi code to uint16. 152759151504615d929945dc59db37bf1166937748c6Steve Block __ SmiAndConstant(code, code, Smi::FromInt(0xffff)); 152859151504615d929945dc59db37bf1166937748c6Steve Block 152959151504615d929945dc59db37bf1166937748c6Steve Block StringCharFromCodeGenerator char_from_code_generator(code, rax); 153059151504615d929945dc59db37bf1166937748c6Steve Block char_from_code_generator.GenerateFast(masm()); 153159151504615d929945dc59db37bf1166937748c6Steve Block __ ret(2 * kPointerSize); 153259151504615d929945dc59db37bf1166937748c6Steve Block 153359151504615d929945dc59db37bf1166937748c6Steve Block ICRuntimeCallHelper call_helper; 153459151504615d929945dc59db37bf1166937748c6Steve Block char_from_code_generator.GenerateSlow(masm(), call_helper); 153559151504615d929945dc59db37bf1166937748c6Steve Block 153659151504615d929945dc59db37bf1166937748c6Steve Block // Tail call the full function. We do not have to patch the receiver 153759151504615d929945dc59db37bf1166937748c6Steve Block // because the function makes no use of it. 153859151504615d929945dc59db37bf1166937748c6Steve Block __ bind(&slow); 153959151504615d929945dc59db37bf1166937748c6Steve Block __ InvokeFunction(function, arguments(), JUMP_FUNCTION); 154059151504615d929945dc59db37bf1166937748c6Steve Block 154159151504615d929945dc59db37bf1166937748c6Steve Block __ bind(&miss); 154259151504615d929945dc59db37bf1166937748c6Steve Block // rcx: function name. 154359151504615d929945dc59db37bf1166937748c6Steve Block Object* obj = GenerateMissBranch(); 154459151504615d929945dc59db37bf1166937748c6Steve Block if (obj->IsFailure()) return obj; 154559151504615d929945dc59db37bf1166937748c6Steve Block 154659151504615d929945dc59db37bf1166937748c6Steve Block // Return the generated code. 154759151504615d929945dc59db37bf1166937748c6Steve Block return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); 154859151504615d929945dc59db37bf1166937748c6Steve Block} 154959151504615d929945dc59db37bf1166937748c6Steve Block 155059151504615d929945dc59db37bf1166937748c6Steve Block 15510d5e116f6aee03185f237311a943491bb079a768Kristian MonsenObject* CallStubCompiler::CompileMathFloorCall(Object* object, 15520d5e116f6aee03185f237311a943491bb079a768Kristian Monsen JSObject* holder, 15530d5e116f6aee03185f237311a943491bb079a768Kristian Monsen JSGlobalPropertyCell* cell, 15540d5e116f6aee03185f237311a943491bb079a768Kristian Monsen JSFunction* function, 15550d5e116f6aee03185f237311a943491bb079a768Kristian Monsen String* name) { 15560d5e116f6aee03185f237311a943491bb079a768Kristian Monsen // TODO(872): implement this. 15570d5e116f6aee03185f237311a943491bb079a768Kristian Monsen return Heap::undefined_value(); 15580d5e116f6aee03185f237311a943491bb079a768Kristian Monsen} 15590d5e116f6aee03185f237311a943491bb079a768Kristian Monsen 15600d5e116f6aee03185f237311a943491bb079a768Kristian Monsen 1561402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei PopescuObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, 1562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 1563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name) { 1564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 1565402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rcx : function name 1566402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[0] : return address 1567402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[8] : argument argc 1568402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[16] : argument argc - 1 1569402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // ... 1570402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[argc * 8] : argument 1 1571402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[(argc + 1) * 8] : argument 0 = receiver 1572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 1573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 1574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 15759dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen GenerateNameCheck(name, &miss); 15769dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 1577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the number of arguments. 1578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const int argc = arguments().immediate(); 1579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LookupResult lookup; 1581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LookupPostInterceptor(holder, name, &lookup); 1582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the receiver from the stack. 1584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 1585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 15866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CallInterceptorCompiler compiler(this, arguments(), rcx); 15876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block compiler.Compile(masm(), 15886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block object, 15896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block holder, 15906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block name, 15916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block &lookup, 15926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block rdx, 15936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block rbx, 15946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block rdi, 15953bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch rax, 15966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block &miss); 1597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Restore receiver. 1599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 1600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the function really is a function. 1602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(rax, &miss); 1603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); 1604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 1605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Patch the receiver on the stack with the global proxy if 1607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // necessary. 1608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (object->IsGlobalObject()) { 1609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); 1610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); 1611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Invoke the function. 1614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdi, rax); 1615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION); 1616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle load cache miss. 1618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 1619bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Object* obj = GenerateMissBranch(); 1620bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch if (obj->IsFailure()) return obj; 1621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 1623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(INTERCEPTOR, name); 1624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* CallStubCompiler::CompileCallGlobal(JSObject* object, 1628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GlobalObject* holder, 1629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSGlobalPropertyCell* cell, 1630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSFunction* function, 1631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name) { 1632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 1633402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rcx : function name 1634402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[0] : return address 1635402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[8] : argument argc 1636402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[16] : argument argc - 1 1637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ... 1638402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[argc * 8] : argument 1 1639402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // rsp[(argc + 1) * 8] : argument 0 = receiver 164059151504615d929945dc59db37bf1166937748c6Steve Block // ----------------------------------- 164159151504615d929945dc59db37bf1166937748c6Steve Block 164259151504615d929945dc59db37bf1166937748c6Steve Block SharedFunctionInfo* function_info = function->shared(); 164359151504615d929945dc59db37bf1166937748c6Steve Block if (function_info->HasCustomCallGenerator()) { 164459151504615d929945dc59db37bf1166937748c6Steve Block const int id = function_info->custom_call_generator_id(); 164559151504615d929945dc59db37bf1166937748c6Steve Block Object* result = CompileCustomCall( 164659151504615d929945dc59db37bf1166937748c6Steve Block id, object, holder, cell, function, name); 164759151504615d929945dc59db37bf1166937748c6Steve Block // undefined means bail out to regular compiler. 164859151504615d929945dc59db37bf1166937748c6Steve Block if (!result->IsUndefined()) return result; 164959151504615d929945dc59db37bf1166937748c6Steve Block } 165059151504615d929945dc59db37bf1166937748c6Steve Block 1651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 1652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 16539dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen GenerateNameCheck(name, &miss); 16549dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 1655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the number of arguments. 1656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const int argc = arguments().immediate(); 1657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 165859151504615d929945dc59db37bf1166937748c6Steve Block GenerateGlobalReceiverCheck(object, holder, name, &miss); 1659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 166059151504615d929945dc59db37bf1166937748c6Steve Block GenerateLoadFunctionFromCell(cell, function, &miss); 1661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Patch the receiver on the stack with the global proxy. 1663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (object->IsGlobalObject()) { 1664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); 1665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); 1666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Setup the context (function already in edi). 1669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); 1670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Jump to the cached code (tail call). 1672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::call_global_inline, 1); 1673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(function->is_compiled()); 1674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Code> code(function->code()); 1675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ParameterCount expected(function->shared()->formal_parameter_count()); 1676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ InvokeCode(code, expected, arguments(), 1677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block RelocInfo::CODE_TARGET, JUMP_FUNCTION); 1678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle call cache miss. 1680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 1681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::call_global_inline_miss, 1); 1682bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Object* obj = GenerateMissBranch(); 1683bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch if (obj->IsFailure()) return obj; 1684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 1686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(NORMAL, name); 1687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1690e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon ClarkeObject* LoadStubCompiler::CompileLoadCallback(String* name, 1691e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke JSObject* object, 1692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 1693e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke AccessorInfo* callback) { 1694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 16957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rax : receiver 1696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rcx : name 1697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 1698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 1699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 1700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1701e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Failure* failure = Failure::InternalError(); 17023bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch bool success = GenerateLoadCallback(object, holder, rax, rcx, rbx, rdx, rdi, 1703e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke callback, name, &miss, &failure); 17040d5e116f6aee03185f237311a943491bb079a768Kristian Monsen if (!success) { 17050d5e116f6aee03185f237311a943491bb079a768Kristian Monsen miss.Unuse(); 17060d5e116f6aee03185f237311a943491bb079a768Kristian Monsen return failure; 17070d5e116f6aee03185f237311a943491bb079a768Kristian Monsen } 1708e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 1709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 1710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateLoadMiss(masm(), Code::LOAD_IC); 1711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 1713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(CALLBACKS, name); 1714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* LoadStubCompiler::CompileLoadConstant(JSObject* object, 1718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 1719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Object* value, 1720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name) { 1721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 17227f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rax : receiver 1723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rcx : name 1724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 1725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 1726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 1727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 17283bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch GenerateLoadConstant(object, holder, rax, rbx, rdx, rdi, value, name, &miss); 1729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 1730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateLoadMiss(masm(), Code::LOAD_IC); 1731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 1733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(CONSTANT_FUNCTION, name); 1734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 17376ded16be15dd865a9b21ea304d5273c8be299c87Steve BlockObject* LoadStubCompiler::CompileLoadNonexistent(String* name, 17386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSObject* object, 17396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSObject* last) { 17406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------- S t a t e ------------- 17417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rax : receiver 17426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rcx : name 17436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[0] : return address 17446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------------------------------- 17456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label miss; 17466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 17476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Chech that receiver is not a smi. 17486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ JumpIfSmi(rax, &miss); 17496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 17506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Check the maps of the full prototype chain. Also check that 17516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // global property cells up to (but not including) the last object 17526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // in the prototype chain are empty. 17533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CheckPrototypes(object, rax, last, rbx, rdx, rdi, name, &miss); 17546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 17556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // If the last object in the prototype chain is a global object, 17566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // check that the global property cell is empty. 17576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (last->IsGlobalObject()) { 17586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Object* cell = GenerateCheckPropertyCell(masm(), 17596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block GlobalObject::cast(last), 17606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block name, 17616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block rdx, 17626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block &miss); 17630d5e116f6aee03185f237311a943491bb079a768Kristian Monsen if (cell->IsFailure()) { 17640d5e116f6aee03185f237311a943491bb079a768Kristian Monsen miss.Unuse(); 17650d5e116f6aee03185f237311a943491bb079a768Kristian Monsen return cell; 17660d5e116f6aee03185f237311a943491bb079a768Kristian Monsen } 17676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 17686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 17696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Return undefined if maps of the full prototype chain are still the 17706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // same and no global property with this name contains a value. 17716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); 17726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ ret(0); 17736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 17746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ bind(&miss); 17756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block GenerateLoadMiss(masm(), Code::LOAD_IC); 17766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 17776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Return the generated code. 17786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block return GetCode(NONEXISTENT, Heap::empty_string()); 17796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 17806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 17816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 1782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* LoadStubCompiler::CompileLoadField(JSObject* object, 1783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 1784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int index, 1785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name) { 1786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 17877f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rax : receiver 1788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rcx : name 1789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 1790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 1791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 1792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 17933bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch GenerateLoadField(object, holder, rax, rbx, rdx, rdi, index, name, &miss); 1794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 1795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateLoadMiss(masm(), Code::LOAD_IC); 1796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 1798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(FIELD, name); 1799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, 1803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 1804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name) { 1805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 18067f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rax : receiver 1807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rcx : name 1808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 1809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 1810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 1811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LookupResult lookup; 1813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LookupPostInterceptor(holder, name, &lookup); 1814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(368): Compile in the whole chain: all the interceptors in 1816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // prototypes and ultimate answer. 1817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateLoadInterceptor(receiver, 1818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block holder, 1819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &lookup, 1820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block rax, 1821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block rcx, 1822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block rdx, 1823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block rbx, 18243bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch rdi, 1825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block name, 1826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &miss); 1827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 1829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateLoadMiss(masm(), Code::LOAD_IC); 1830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 1832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(INTERCEPTOR, name); 1833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object, 1837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GlobalObject* holder, 1838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSGlobalPropertyCell* cell, 1839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name, 1840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool is_dont_delete) { 1841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 18427f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rax : receiver 1843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rcx : name 1844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 1845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 1846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 1847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the object is the holder then we know that it's a global 1849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // object which can only happen for contextual loads. In this case, 1850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the receiver cannot be a smi. 1851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (object != holder) { 1852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(rax, &miss); 1853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the maps haven't changed. 18563bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch CheckPrototypes(object, rax, holder, rbx, rdx, rdi, name, &miss); 1857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the value from the cell. 18597f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ Move(rbx, Handle<JSGlobalPropertyCell>(cell)); 18607f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset)); 1861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check for deleted property if property can actually be deleted. 1863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!is_dont_delete) { 18647f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); 1865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(equal, &miss); 1866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (FLAG_debug_code) { 18677f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); 1868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Check(not_equal, "DontDelete cells can't contain the hole"); 1869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 18710d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ IncrementCounter(&Counters::named_load_global_stub, 1); 18727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ movq(rax, rbx); 1873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 1874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 18760d5e116f6aee03185f237311a943491bb079a768Kristian Monsen __ IncrementCounter(&Counters::named_load_global_stub_miss, 1); 1877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateLoadMiss(masm(), Code::LOAD_IC); 1878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 1880a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(NORMAL, name); 1881a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadStubCompiler::CompileLoadCallback(String* name, 1885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* receiver, 1886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 1887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AccessorInfo* callback) { 1888a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 18897f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rax : key 18907f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rdx : receiver 1891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 1892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 1893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 1894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::keyed_load_callback, 1); 1896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the name has not changed. 1898a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Cmp(rax, Handle<String>(name)); 1899a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 1900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1901e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Failure* failure = Failure::InternalError(); 19023bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch bool success = GenerateLoadCallback(receiver, holder, rdx, rax, rbx, rcx, rdi, 1903e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke callback, name, &miss, &failure); 19040d5e116f6aee03185f237311a943491bb079a768Kristian Monsen if (!success) { 19050d5e116f6aee03185f237311a943491bb079a768Kristian Monsen miss.Unuse(); 19060d5e116f6aee03185f237311a943491bb079a768Kristian Monsen return failure; 19070d5e116f6aee03185f237311a943491bb079a768Kristian Monsen } 1908e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 1909a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 1910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ DecrementCounter(&Counters::keyed_load_callback, 1); 1911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 1912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 1914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(CALLBACKS, name); 1915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1917a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { 1919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 19207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rax : key 19217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rdx : receiver 1922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 1923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 1924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 1925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::keyed_load_array_length, 1); 1927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the name has not changed. 1929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Cmp(rax, Handle<String>(name)); 1930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 1931a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 19327f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch GenerateLoadArrayLength(masm(), rdx, rcx, &miss); 1933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 1934a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ DecrementCounter(&Counters::keyed_load_array_length, 1); 1935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 1936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 1938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(CALLBACKS, name); 1939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1940a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1941a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name, 1943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* receiver, 1944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 1945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Object* value) { 1946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 19477f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rax : key 19487f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rdx : receiver 1949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 1950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 1951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 1952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::keyed_load_constant_function, 1); 1954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the name has not changed. 1956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Cmp(rax, Handle<String>(name)); 1957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 1958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 19593bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch GenerateLoadConstant(receiver, holder, rdx, rbx, rcx, rdi, 1960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value, name, &miss); 1961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 1962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ DecrementCounter(&Counters::keyed_load_constant_function, 1); 1963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 1964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 1966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(CONSTANT_FUNCTION, name); 1967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { 1971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 19727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rax : key 19737f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rdx : receiver 1974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 1975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 1976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 1977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::keyed_load_function_prototype, 1); 1979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the name has not changed. 1981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Cmp(rax, Handle<String>(name)); 1982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 1983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 19847f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss); 1985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 1986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ DecrementCounter(&Counters::keyed_load_function_prototype, 1); 1987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 1988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1989a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 1990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(CALLBACKS, name); 1991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, 1995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 1996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name) { 1997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 19987f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rax : key 19997f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rdx : receiver 2000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 2001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 2003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::keyed_load_interceptor, 1); 2005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the name has not changed. 2007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Cmp(rax, Handle<String>(name)); 2008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 2009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LookupResult lookup; 2011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LookupPostInterceptor(holder, name, &lookup); 2012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateLoadInterceptor(receiver, 2013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block holder, 2014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &lookup, 2015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block rdx, 20167f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch rax, 20177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch rcx, 2018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block rbx, 20193bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch rdi, 2020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block name, 2021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &miss); 2022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 2023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ DecrementCounter(&Counters::keyed_load_interceptor, 1); 2024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 2025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 2027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(INTERCEPTOR, name); 2028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { 2032a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 20337f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rax : key 20347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rdx : receiver 20357f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rsp[0] : return address 2036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 2038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::keyed_load_string_length, 1); 2040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the name has not changed. 2042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Cmp(rax, Handle<String>(name)); 2043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 2044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 20457f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss); 2046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 2047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ DecrementCounter(&Counters::keyed_load_string_length, 1); 2048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 2049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 2051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(CALLBACKS, name); 2052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* StoreStubCompiler::CompileStoreCallback(JSObject* object, 2056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AccessorInfo* callback, 2057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name) { 2058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 2059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rax : value 2060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rcx : name 20614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // -- rdx : receiver 2062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 2063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 2065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the object isn't a smi. 20674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ JumpIfSmi(rdx, &miss); 2068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the map of the object hasn't changed. 20704515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), 2071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Map>(object->map())); 2072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 2073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Perform global security token check if needed. 2075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (object->IsJSGlobalProxy()) { 20764515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ CheckAccessGlobalProxy(rdx, rbx, &miss); 2077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Stub never generated for non-global objects that require access 2080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // checks. 2081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); 2082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rbx); // remove the return address 20844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ push(rdx); // receiver 2085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Push(Handle<AccessorInfo>(callback)); // callback info 2086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rcx); // name 2087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rax); // value 2088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rbx); // restore return address 2089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Do tail-call to the runtime system. 2091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference store_callback_property = 2092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference(IC_Utility(IC::kStoreCallbackProperty)); 20936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ TailCallExternalReference(store_callback_property, 4, 1); 2094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle store cache miss. 2096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 2097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); 2098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Jump(ic, RelocInfo::CODE_TARGET); 2099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 2101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(CALLBACKS, name); 2102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* StoreStubCompiler::CompileStoreField(JSObject* object, 2106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int index, 2107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Map* transition, 2108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name) { 2109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 2110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rax : value 2111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rcx : name 21124515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // -- rdx : receiver 2113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 2114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 2116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2117402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Generate store field code. Preserves receiver and name on jump to miss. 2118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateStoreField(masm(), 2119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block object, 2120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index, 2121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block transition, 21224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke rdx, rcx, rbx, 2123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &miss); 2124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle store cache miss. 2126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 2127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); 2128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Jump(ic, RelocInfo::CODE_TARGET); 2129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 2131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); 2132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, 2136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name) { 2137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 2138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rax : value 2139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rcx : name 21404515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // -- rdx : receiver 2141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 2142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 2144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the object isn't a smi. 21464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ JumpIfSmi(rdx, &miss); 2147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the map of the object hasn't changed. 21494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), 2150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Map>(receiver->map())); 2151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 2152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Perform global security token check if needed. 2154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (receiver->IsJSGlobalProxy()) { 21554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ CheckAccessGlobalProxy(rdx, rbx, &miss); 2156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Stub never generated for non-global objects that require access 2159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // checks. 2160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); 2161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rbx); // remove the return address 21634515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ push(rdx); // receiver 2164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rcx); // name 2165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rax); // value 2166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rbx); // restore return address 2167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Do tail-call to the runtime system. 2169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference store_ic_property = 2170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); 21716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ TailCallExternalReference(store_ic_property, 3, 1); 2172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle store cache miss. 2174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 2175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); 2176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Jump(ic, RelocInfo::CODE_TARGET); 2177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 2179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(INTERCEPTOR, name); 2180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, 2184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSGlobalPropertyCell* cell, 2185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name) { 2186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 2187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rax : value 2188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rcx : name 21894515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // -- rdx : receiver 2190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 2191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 2193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the map of the global has not changed. 21954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), 2196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Map>(object->map())); 2197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 2198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Store the value in the cell. 2200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Move(rcx, Handle<JSGlobalPropertyCell>(cell)); 2201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(FieldOperand(rcx, JSGlobalPropertyCell::kValueOffset), rax); 2202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the value (register rax). 2204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::named_store_global_inline, 1); 2205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 2206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle store cache miss. 2208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 2209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::named_store_global_inline_miss, 1); 2210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); 2211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Jump(ic, RelocInfo::CODE_TARGET); 2212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 2214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(NORMAL, name); 2215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadStubCompiler::CompileLoadField(String* name, 2219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* receiver, 2220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 2221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int index) { 2222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 22237f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rax : key 22247f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rdx : receiver 22257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // -- rsp[0] : return address 2226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 2228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::keyed_load_field, 1); 2230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the name has not changed. 2232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Cmp(rax, Handle<String>(name)); 2233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 2234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 22353bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss); 2236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 2238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ DecrementCounter(&Counters::keyed_load_field, 1); 2239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 2240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 2242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(FIELD, name); 2243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, 2247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int index, 2248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Map* transition, 2249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name) { 2250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 2251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rax : value 2252f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // -- rcx : key 2253f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // -- rdx : receiver 2254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 2255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 2257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::keyed_store_field, 1); 2259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the name has not changed. 2261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Cmp(rcx, Handle<String>(name)); 2262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 2263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2264402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Generate store field code. Preserves receiver and name on jump to miss. 2265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateStoreField(masm(), 2266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block object, 2267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index, 2268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block transition, 2269402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu rdx, rcx, rbx, 2270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &miss); 2271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle store cache miss. 2273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 2274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ DecrementCounter(&Counters::keyed_store_field, 1); 2275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); 2276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Jump(ic, RelocInfo::CODE_TARGET); 2277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 2279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); 2280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadInterceptor(JSObject* object, 22847f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch JSObject* interceptor_holder, 2285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LookupResult* lookup, 2286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 2287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register name_reg, 2288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch1, 2289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch2, 22903bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register scratch3, 2291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name, 2292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* miss) { 22937f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch ASSERT(interceptor_holder->HasNamedInterceptor()); 22947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); 22957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 22967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Check that the receiver isn't a smi. 22977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ JumpIfSmi(receiver, miss); 22987f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 22997f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // So far the most popular follow ups for interceptor loads are FIELD 23007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // and CALLBACKS, so inline only them, other cases may be added 23017f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // later. 23027f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch bool compile_followup_inline = false; 23037f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch if (lookup->IsProperty() && lookup->IsCacheable()) { 23047f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch if (lookup->type() == FIELD) { 23057f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch compile_followup_inline = true; 23067f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } else if (lookup->type() == CALLBACKS && 23077f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch lookup->GetCallbackObject()->IsAccessorInfo() && 23087f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) { 23097f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch compile_followup_inline = true; 23107f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } 23117f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } 23127f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 23137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch if (compile_followup_inline) { 23147f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Compile the interceptor call, followed by inline code to load the 23157f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // property from further up the prototype chain if the call fails. 23167f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Check that the maps haven't changed. 23177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, 23183bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch1, scratch2, scratch3, 23193bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch name, miss); 23207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); 23217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 23227f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Save necessary data before invoking an interceptor. 23237f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Requires a frame to make GC aware of pushed pointers. 23247f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ EnterInternalFrame(); 23257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 23267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { 23277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // CALLBACKS case needs a receiver to be passed into C++ callback. 23287f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ push(receiver); 23297f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } 23307f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ push(holder_reg); 23317f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ push(name_reg); 23327f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 23337f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Invoke an interceptor. Note: map checks from receiver to 23347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // interceptor's holder has been compiled before (see a caller 23357f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // of this method.) 23367f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch CompileCallLoadPropertyWithInterceptor(masm(), 23377f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch receiver, 23387f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch holder_reg, 23397f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch name_reg, 23407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch interceptor_holder); 23417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 23427f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Check if interceptor provided a value for property. If it's 23437f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // the case, return immediately. 23447f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch Label interceptor_failed; 23457f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); 23467f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ j(equal, &interceptor_failed); 23477f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ LeaveInternalFrame(); 23487f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ ret(0); 23497f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 23507f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ bind(&interceptor_failed); 23517f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ pop(name_reg); 23527f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ pop(holder_reg); 23537f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { 23547f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ pop(receiver); 23557f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } 23567f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 23577f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ LeaveInternalFrame(); 23587f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 23597f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Check that the maps from interceptor's holder to lookup's holder 23607f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // haven't changed. And load lookup's holder into |holder| register. 23617f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch if (interceptor_holder != lookup->holder()) { 23627f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch holder_reg = CheckPrototypes(interceptor_holder, 23637f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch holder_reg, 23647f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch lookup->holder(), 23657f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch scratch1, 23667f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch scratch2, 23673bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch3, 23687f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch name, 23697f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch miss); 23707f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } 23717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 23727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch if (lookup->type() == FIELD) { 23737f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // We found FIELD property in prototype chain of interceptor's holder. 23747f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Retrieve a field from field's holder. 23757f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch GenerateFastPropertyLoad(masm(), rax, holder_reg, 23767f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch lookup->holder(), lookup->GetFieldIndex()); 23777f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ ret(0); 23787f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } else { 23797f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // We found CALLBACKS property in prototype chain of interceptor's 23807f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // holder. 23817f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch ASSERT(lookup->type() == CALLBACKS); 23827f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); 23837f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); 23847f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch ASSERT(callback != NULL); 23857f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch ASSERT(callback->getter() != NULL); 23867f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 23877f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Tail call to runtime. 23887f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Important invariant in CALLBACKS case: the code above must be 23897f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // structured to never clobber |receiver| register. 23907f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ pop(scratch2); // return address 23917f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ push(receiver); 23927f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ push(holder_reg); 23937f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ Move(holder_reg, Handle<AccessorInfo>(callback)); 23947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ push(holder_reg); 23957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset)); 23967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ push(name_reg); 23977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ push(scratch2); // restore return address 23987f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 23997f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch ExternalReference ref = 24007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); 24017f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ TailCallExternalReference(ref, 5, 1); 24027f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } 24037f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } else { // !compile_followup_inline 24047f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Call the runtime system to load the interceptor. 24057f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // Check that the maps haven't changed. 24067f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, 24073bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch1, scratch2, scratch3, 24083bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch name, miss); 24097f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ pop(scratch2); // save old return address 24107f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch PushInterceptorArguments(masm(), receiver, holder_reg, 24117f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch name_reg, interceptor_holder); 24127f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ push(scratch2); // restore old return address 24137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 24147f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch ExternalReference ref = ExternalReference( 24157f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); 24167f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch __ TailCallExternalReference(ref, 5, 1); 24177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } 2418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2421e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkebool StubCompiler::GenerateLoadCallback(JSObject* object, 2422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 2423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 2424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register name_reg, 2425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch1, 2426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch2, 24273bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register scratch3, 2428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block AccessorInfo* callback, 2429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name, 2430e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Label* miss, 2431e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke Failure** failure) { 2432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the receiver isn't a smi. 2433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(receiver, miss); 2434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the maps haven't changed. 2436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register reg = 2437bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch CheckPrototypes(object, receiver, holder, scratch1, 2438bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch scratch2, scratch3, name, miss); 2439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2440bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Handle<AccessorInfo> callback_handle(callback); 2441bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch 2442bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ EnterInternalFrame(); 2443bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ PushHandleScope(scratch2); 2444bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // Push the stack address where the list of arguments ends. 2445bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ movq(scratch2, rsp); 2446bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ subq(scratch2, Immediate(2 * kPointerSize)); 2447bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ push(scratch2); 2448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(receiver); // receiver 2449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(reg); // holder 2450bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch if (Heap::InNewSpace(callback_handle->data())) { 2451bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ Move(scratch2, callback_handle); 2452bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ push(FieldOperand(scratch2, AccessorInfo::kDataOffset)); // data 2453bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch } else { 2454bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ Push(Handle<Object>(callback_handle->data())); 2455bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch } 2456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(name_reg); // name 2457bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // Save a pointer to where we pushed the arguments pointer. 2458bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // This will be passed as the const AccessorInfo& to the C++ callback. 2459bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch 2460bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch#ifdef _WIN64 2461bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // Win64 uses first register--rcx--for returned value. 2462bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Register accessor_info_arg = r8; 2463bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Register name_arg = rdx; 2464bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch#else 2465bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Register accessor_info_arg = rdx; // temporary, copied to rsi by the stub. 2466bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Register name_arg = rdi; 2467bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch#endif 2468bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch 2469bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ movq(accessor_info_arg, rsp); 2470bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ addq(accessor_info_arg, Immediate(4 * kPointerSize)); 2471bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ movq(name_arg, rsp); 2472bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch 2473bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // Do call through the api. 2474bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch ASSERT_EQ(5, ApiGetterEntryStub::kStackSpace); 2475bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Address getter_address = v8::ToCData<Address>(callback->getter()); 2476bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch ApiFunction fun(getter_address); 2477bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch ApiGetterEntryStub stub(callback_handle, &fun); 2478bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch#ifdef _WIN64 2479bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // We need to prepare a slot for result handle on stack and put 2480bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // a pointer to it into 1st arg register. 2481bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ push(Immediate(0)); 2482bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ movq(rcx, rsp); 2483bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch#endif 2484bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // Emitting a stub call may try to allocate (if the code is not 2485bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // already generated). Do not allow the assembler to perform a 2486bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // garbage collection but instead return the allocation failure 2487bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // object. 2488bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Object* result = masm()->TryCallStub(&stub); 2489bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch if (result->IsFailure()) { 2490bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch *failure = Failure::cast(result); 2491bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch return false; 2492bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch } 2493bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch#ifdef _WIN64 2494bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // Discard allocated slot. 2495bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ addq(rsp, Immediate(kPointerSize)); 2496bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch#endif 2497bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch 2498bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // We need to avoid using rax since that now holds the result. 2499bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch Register tmp = scratch2.is(rax) ? reg : scratch2; 2500bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // Emitting PopHandleScope may try to allocate. Do not allow the 2501bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // assembler to perform a garbage collection but instead return a 2502bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch // failure object. 2503bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch result = masm()->TryPopHandleScope(rax, tmp); 2504bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch if (result->IsFailure()) { 2505bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch *failure = Failure::cast(result); 2506bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch return false; 2507bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch } 2508bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ LeaveInternalFrame(); 2509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2510bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch __ ret(0); 2511e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 2512e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke return true; 2513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockRegister StubCompiler::CheckPrototypes(JSObject* object, 2517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register object_reg, 2518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 2519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register holder_reg, 25203bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register scratch1, 25213bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register scratch2, 2522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name, 2523402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu int save_at_depth, 25243bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Label* miss) { 25253bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Make sure there's no overlap between holder and object registers. 25263bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); 25273bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) 25283bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch && !scratch2.is(scratch1)); 25293bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 25303bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Keep track of the current object in register reg. On the first 25313bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // iteration, reg is an alias for object_reg, on later iterations, 25323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // it is an alias for holder_reg. 25333bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register reg = object_reg; 25343bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch int depth = 0; 25353bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 25363bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (save_at_depth == depth) { 25373bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(Operand(rsp, kPointerSize), object_reg); 25383bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 25393bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 25403bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Check the maps in the prototype chain. 25413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Traverse the prototype chain from the object and do map checks. 25423bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch JSObject* current = object; 25433bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch while (current != holder) { 25443bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch depth++; 25453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 25463bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Only global objects and objects that do not require access 25473bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // checks are allowed in stubs. 25483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); 25493bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 25503bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch JSObject* prototype = JSObject::cast(current->GetPrototype()); 25513bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (!current->HasFastProperties() && 25523bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch !current->IsJSGlobalObject() && 25533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch !current->IsJSGlobalProxy()) { 25543bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (!name->IsSymbol()) { 25553bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Object* lookup_result = Heap::LookupSymbol(name); 25563bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (lookup_result->IsFailure()) { 25573bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch set_failure(Failure::cast(lookup_result)); 25583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch return reg; 25593bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } else { 25603bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch name = String::cast(lookup_result); 25613bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 25623bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 25633bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch ASSERT(current->property_dictionary()->FindEntry(name) == 25643bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch StringDictionary::kNotFound); 25653bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 25663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch GenerateDictionaryNegativeLookup(masm(), 25673bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch miss, 25683bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch reg, 25693bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch name, 25703bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch1, 25713bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch2); 25723bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); 25733bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch reg = holder_reg; // from now the object is in holder_reg 25743bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); 25753bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } else if (Heap::InNewSpace(prototype)) { 25763bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Get the map of the current object. 25773bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); 25783bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ Cmp(scratch1, Handle<Map>(current->map())); 25793bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Branch on the result of the map check. 25803bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(not_equal, miss); 25813bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Check access rights to the global object. This has to happen 25823bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // after the map check so that we know that the object is 25833bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // actually a global object. 25843bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (current->IsJSGlobalProxy()) { 25853bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ CheckAccessGlobalProxy(reg, scratch1, miss); 25863bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 25873bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Restore scratch register to be the map of the object. 25883bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // We load the prototype from the map in the scratch register. 25893bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); 25903bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 25913bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // The prototype is in new space; we cannot store a reference 25923bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // to it in the code. Load it from the map. 25933bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch reg = holder_reg; // from now the object is in holder_reg 25943bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); 25953bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 25963bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } else { 25973bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Check the map of the current object. 25983bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), 25993bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Handle<Map>(current->map())); 26003bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Branch on the result of the map check. 26013bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(not_equal, miss); 26023bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Check access rights to the global object. This has to happen 26033bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // after the map check so that we know that the object is 26043bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // actually a global object. 26053bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (current->IsJSGlobalProxy()) { 26063bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ CheckAccessGlobalProxy(reg, scratch1, miss); 26073bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 26083bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // The prototype is in old space; load it directly. 26093bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch reg = holder_reg; // from now the object is in holder_reg 26103bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ Move(reg, Handle<JSObject>(prototype)); 26113bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 26123bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 26133bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (save_at_depth == depth) { 26143bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(Operand(rsp, kPointerSize), reg); 26153bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 26163bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 26173bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Go to the next object in the prototype chain. 26183bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch current = prototype; 26193bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 26203bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 26213bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Check the holder map. 26223bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), Handle<Map>(holder->map())); 26233bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(not_equal, miss); 26243bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 26253bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Log the check depth. 26263bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch LOG(IntEvent("check-maps-depth", depth + 1)); 26273bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 26283bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Perform security check for access to the global object and return 26293bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // the holder register. 26303bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch ASSERT(current == holder); 26313bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); 26323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (current->IsJSGlobalProxy()) { 26333bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ CheckAccessGlobalProxy(reg, scratch1, miss); 26343bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 2635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If we've skipped any global objects, it's not enough to verify 26376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // that their maps haven't changed. We also need to check that the 26386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // property cell for the property is still empty. 26393bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch current = object; 26403bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch while (current != holder) { 26413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (current->IsGlobalObject()) { 26426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Object* cell = GenerateCheckPropertyCell(masm(), 26433bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch GlobalObject::cast(current), 26446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block name, 26453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch1, 26466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block miss); 26476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (cell->IsFailure()) { 26486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block set_failure(Failure::cast(cell)); 26493bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch return reg; 2650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 26523bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch current = JSObject::cast(current->GetPrototype()); 2653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the register containing the holder. 26563bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch return reg; 2657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadField(JSObject* object, 2661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 2662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 2663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch1, 2664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch2, 26653bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register scratch3, 2666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int index, 2667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name, 2668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* miss) { 2669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the receiver isn't a smi. 2670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(receiver, miss); 2671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check the prototype chain. 2673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register reg = 2674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CheckPrototypes(object, receiver, holder, 26753bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch1, scratch2, scratch3, name, miss); 2676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the value from the properties. 2678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateFastPropertyLoad(masm(), rax, reg, holder, index); 2679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 2680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadConstant(JSObject* object, 2684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder, 2685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 2686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch1, 2687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch2, 26883bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register scratch3, 2689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Object* value, 2690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block String* name, 2691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* miss) { 2692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the receiver isn't a smi. 2693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(receiver, miss); 2694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the maps haven't changed. 2696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register reg = 2697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CheckPrototypes(object, receiver, holder, 26983bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch1, scratch2, scratch3, name, miss); 2699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the constant value. 2701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Move(rax, Handle<Object>(value)); 2702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 2703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Specialized stub for constructing objects from functions which only have only 2707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// simple assignments of the form this.x = ...; in their body. 2708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* ConstructStubCompiler::CompileConstructStub( 2709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block SharedFunctionInfo* shared) { 2710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 2711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rax : argc 2712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rdi : constructor 2713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 2714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[4] : last argument 2715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label generic_stub_call; 2717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Use r8 for holding undefined which is used in several places below. 2719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Move(r8, Factory::undefined_value()); 2720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_DEBUGGER_SUPPORT 2722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check to see whether there are any break points in the function code. If 2723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // there are jump to the generic constructor stub which calls the actual 2724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // code for the function thereby hitting the break points. 2725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); 2726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kDebugInfoOffset)); 2727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rbx, r8); 2728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &generic_stub_call); 2729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 2730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the initial map and verify that it is in fact a map. 2732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); 2733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Will both indicate a NULL and a Smi. 2734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(kSmiTag == 0); 2735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(rbx, &generic_stub_call); 2736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(rbx, MAP_TYPE, rcx); 2737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &generic_stub_call); 2738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG 2740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Cannot construct functions this way. 2741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdi: constructor 2742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbx: initial map 2743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpInstanceType(rbx, JS_FUNCTION_TYPE); 2744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Assert(not_equal, "Function constructed by construct stub."); 2745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 2746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Now allocate the JSObject in new space. 2748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdi: constructor 2749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbx: initial map 2750a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset)); 2751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ shl(rcx, Immediate(kPointerSizeLog2)); 2752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ AllocateInNewSpace(rcx, 2753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block rdx, 2754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block rcx, 2755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block no_reg, 2756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &generic_stub_call, 2757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block NO_ALLOCATION_FLAGS); 2758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Allocated the JSObject, now initialize the fields and add the heap tag. 2760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbx: initial map 2761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdx: JSObject (untagged) 2762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rdx, JSObject::kMapOffset), rbx); 2763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Move(rbx, Factory::empty_fixed_array()); 2764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rdx, JSObject::kPropertiesOffset), rbx); 2765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rdx, JSObject::kElementsOffset), rbx); 2766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: argc 2768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdx: JSObject (untagged) 2769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the address of the first in-object property into r9. 2770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ lea(r9, Operand(rdx, JSObject::kHeaderSize)); 2771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Calculate the location of the first argument. The stack contains only the 2772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // return address on top of the argc arguments. 2773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ lea(rcx, Operand(rsp, rax, times_pointer_size, 0)); 2774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: argc 2776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rcx: first argument 2777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdx: JSObject (untagged) 2778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // r8: undefined 2779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // r9: first in-object property of the JSObject 2780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fill the initialized properties with a constant value or a passed argument 2781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // depending on the this.x = ...; assignment in the function. 2782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < shared->this_property_assignments_count(); i++) { 2783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (shared->IsThisPropertyAssignmentArgument(i)) { 2784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the argument assigned to the property is actually passed. 2785e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // If argument is not passed the property is set to undefined, 2786e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // otherwise find it on the stack. 2787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int arg_number = shared->GetThisPropertyAssignmentArgument(i); 2788e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rbx, r8); 2789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rax, Immediate(arg_number)); 2790e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ cmovq(above, rbx, Operand(rcx, arg_number * -kPointerSize)); 2791e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Store value in the property. 2792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(r9, i * kPointerSize), rbx); 2793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 2794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Set the property to the constant value. 2795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i)); 2796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Move(Operand(r9, i * kPointerSize), constant); 2797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fill the unused in-object property fields with undefined. 2801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = shared->this_property_assignments_count(); 2802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i < shared->CalculateInObjectProperties(); 2803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i++) { 2804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(r9, i * kPointerSize), r8); 2805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: argc 2808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdx: JSObject (untagged) 2809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Move argc to rbx and the JSObject to return to rax and tag it. 2810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbx, rax); 2811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, rdx); 2812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ or_(rax, Immediate(kHeapObjectTag)); 2813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: JSObject 2815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbx: argc 2816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Remove caller arguments and receiver from the stack and return. 2817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rcx); 2818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ lea(rsp, Operand(rsp, rbx, times_pointer_size, 1 * kPointerSize)); 2819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rcx); 2820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::constructed_objects, 1); 2821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ IncrementCounter(&Counters::constructed_objects_stub, 1); 2822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 2823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Jump to the generic stub in case the specialized code cannot handle the 2825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // construction. 2826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&generic_stub_call); 2827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); 2828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Code> generic_construct_stub(code); 2829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); 2830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 2832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(); 2833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __ 2837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} } // namespace v8::internal 2839f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke 2840f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#endif // V8_TARGET_ARCH_X64 2841