stub-cache-x64.cc revision 8b112d2025046f85ef7f6be087c6129c872ebad2
1e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// Copyright 2011 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#include "v8.h" 29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 30f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#if defined(V8_TARGET_ARCH_X64) 31f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke 32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "ic-inl.h" 338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch#include "codegen.h" 34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "stub-cache.h" 35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 { 37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal { 38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM(masm) 40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4244f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstatic void ProbeTable(Isolate* isolate, 4344f0eee88ff00398ff7f715fab053374d808c90dSteve Block MacroAssembler* masm, 44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Code::Flags flags, 45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block StubCache::Table table, 46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register name, 47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register offset) { 483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block ASSERT_EQ(8, kPointerSize); 493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block ASSERT_EQ(16, sizeof(StubCache::Entry)); 503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // The offset register holds the entry offset times four (due to masking 513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // and shifting optimizations). 5244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); 53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadAddress(kScratchRegister, key_offset); 56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the key in the entry matches the name. 573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // Multiply entry offset by 16 to get the entry address. Since the 583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // offset register already holds the entry offset times four, multiply 593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block // by a further four. 603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block __ cmpl(name, Operand(kScratchRegister, offset, times_4, 0)); 61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the code entry from the cache. 63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Use key_offset + kPointerSize, rather than loading value_offset. 64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(kScratchRegister, 653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block Operand(kScratchRegister, offset, times_4, kPointerSize)); 66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the flags match what we're looking for. 67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movl(offset, FieldOperand(kScratchRegister, Code::kFlagsOffset)); 68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ and_(offset, Immediate(~Code::kFlagsNotUsedInLookup)); 69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpl(offset, Immediate(flags)); 70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Jump to the first instruction in the code stub. 73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ addq(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag)); 74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ jmp(kScratchRegister); 75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 803bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// Helper function used to check that the dictionary doesn't contain 813bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// the property. This function may return false negatives, so miss_label 823bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// must always call a backup property check that is complete. 833bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// This function is safe to call if the receiver has fast properties. 843bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// Name must be a symbol and receiver must be a heap object. 853bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdochstatic void GenerateDictionaryNegativeLookup(MacroAssembler* masm, 863bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Label* miss_label, 873bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register receiver, 883bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch String* name, 893bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register r0, 903bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register r1) { 913bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch ASSERT(name->IsSymbol()); 9244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 9344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->negative_lookups(), 1); 9444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->negative_lookups_miss(), 1); 953bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 963bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Label done; 973bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(r0, FieldOperand(receiver, HeapObject::kMapOffset)); 983bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 993bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const int kInterceptorOrAccessCheckNeededMask = 1003bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); 1013bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1023bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Bail out if the receiver has a named interceptor or requires access checks. 1033bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ testb(FieldOperand(r0, Map::kBitFieldOffset), 1043bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Immediate(kInterceptorOrAccessCheckNeededMask)); 1053bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(not_zero, miss_label); 1063bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1073bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Check that receiver is a JSObject. 1083bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ CmpInstanceType(r0, FIRST_JS_OBJECT_TYPE); 1093bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(below, miss_label); 1103bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1113bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Load properties array. 1123bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register properties = r0; 1133bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(properties, FieldOperand(receiver, JSObject::kPropertiesOffset)); 1143bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1153bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Check that the properties array is a dictionary. 1163bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset), 1173bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Heap::kHashTableMapRootIndex); 1183bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(not_equal, miss_label); 1193bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1203bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Compute the capacity mask. 1213bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const int kCapacityOffset = 1223bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch StringDictionary::kHeaderSize + 1233bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch StringDictionary::kCapacityIndex * kPointerSize; 1243bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1253bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Generate an unrolled loop that performs a few probes before 1263bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // giving up. 1273bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch static const int kProbes = 4; 1283bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch const int kElementsStartOffset = 1293bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch StringDictionary::kHeaderSize + 1303bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch StringDictionary::kElementsStartIndex * kPointerSize; 1313bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // If names of slots in range from 1 to kProbes - 1 for the hash value are 1333bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // not equal to the name and kProbes-th slot is not used (its name is the 1343bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // undefined value), it guarantees the hash table doesn't contain the 1353bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // property. It's true even if some slots represent deleted properties 1363bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // (their names are the null value). 1373bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch for (int i = 0; i < kProbes; i++) { 1383bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // r0 points to properties hash. 1393bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Compute the masked index: (hash + i + i * i) & mask. 1403bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register index = r1; 1413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Capacity is smi 2^n. 1423bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset)); 1433bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ decl(index); 1443bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ and_(index, 1453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Immediate(name->Hash() + StringDictionary::GetProbeOffset(i))); 1463bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1473bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Scale the index by multiplying by the entry size. 1483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch ASSERT(StringDictionary::kEntrySize == 3); 1493bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. 1503bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1513bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register entity_name = r1; 1523bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Having undefined at this place means the name is not contained. 1533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch ASSERT_EQ(kSmiTagSize, 1); 1543bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(entity_name, Operand(properties, index, times_pointer_size, 1553bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch kElementsStartOffset - kHeapObjectTag)); 15644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Cmp(entity_name, masm->isolate()->factory()->undefined_value()); 1573bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // __ jmp(miss_label); 1583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch if (i != kProbes - 1) { 1593bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(equal, &done); 1603bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1613bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Stop if found the property. 1623bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ Cmp(entity_name, Handle<String>(name)); 1633bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(equal, miss_label); 1643bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1653bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Check if the entry name is not a symbol. 1663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); 1673bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset), 1683bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Immediate(kIsSymbolMask)); 1693bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(zero, miss_label); 1703bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } else { 1713bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch // Give up probing if still not found the undefined value. 1723bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ j(not_equal, miss_label); 1733bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 1743bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch } 1753bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1763bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch __ bind(&done); 17744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ DecrementCounter(counters->negative_lookups_miss(), 1); 1783bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch} 1793bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 1803bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCache::GenerateProbe(MacroAssembler* masm, 182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Code::Flags flags, 183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register name, 185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch, 1863e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu Register extra, 1873e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu Register extra2) { 18844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate* isolate = masm->isolate(); 189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 1903e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu USE(extra); // The register extra is not used on the X64 platform. 1913e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu USE(extra2); // The register extra2 is not used on the X64 platform. 192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Make sure that code is valid. The shifting code relies on the 193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // entry size being 16. 194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(sizeof(Entry) == 16); 195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Make sure the flags do not name a specific type. 197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(Code::ExtractTypeFromFlags(flags) == 0); 198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Make sure that there are no register conflicts. 200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!scratch.is(receiver)); 201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(!scratch.is(name)); 202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2033e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu // Check scratch register is valid, extra and extra2 are unused. 2043e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu ASSERT(!scratch.is(no_reg)); 2053e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu ASSERT(extra2.is(no_reg)); 2063e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu 207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the receiver isn't a smi. 208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(receiver, &miss); 209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the map of the receiver and compute the hash. 211d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movl(scratch, FieldOperand(name, String::kHashFieldOffset)); 212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Use only the low 32 bits of the map pointer. 213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); 214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ xor_(scratch, Immediate(flags)); 215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize)); 216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Probe the primary table. 21844f0eee88ff00398ff7f715fab053374d808c90dSteve Block ProbeTable(isolate, masm, flags, kPrimary, name, scratch); 219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Primary miss: Compute hash for secondary probe. 221d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block __ movl(scratch, FieldOperand(name, String::kHashFieldOffset)); 222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); 223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ xor_(scratch, Immediate(flags)); 224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize)); 225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ subl(scratch, name); 226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ addl(scratch, Immediate(flags)); 227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ and_(scratch, Immediate((kSecondaryTableSize - 1) << kHeapObjectTagSize)); 228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Probe the secondary table. 23044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ProbeTable(isolate, masm, flags, kSecondary, name, scratch); 231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Cache miss: Fall-through and let caller handle the miss by 233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // entering the runtime system. 234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, 2399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block int index, 2409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register prototype) { 2419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Load the global or builtins object from the current context. 2429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(prototype, 2439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); 2449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Load the global context from the global or builtins object. 2459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(prototype, 2469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block FieldOperand(prototype, GlobalObject::kGlobalContextOffset)); 2479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Load the function from the global context. 2489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(prototype, Operand(prototype, Context::SlotOffset(index))); 2499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Load the initial map. The global functions all have initial maps. 2509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(prototype, 2519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset)); 2529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Load the prototype from the initial map. 2539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); 2549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( 2589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block MacroAssembler* masm, int index, Register prototype, Label* miss) { 25944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate* isolate = masm->isolate(); 2609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check we're still in the same context. 26144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Move(prototype, isolate->global()); 2629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)), 2639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block prototype); 2649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, miss); 2659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the global function with the given index. 26644f0eee88ff00398ff7f715fab053374d808c90dSteve Block JSFunction* function = 26744f0eee88ff00398ff7f715fab053374d808c90dSteve Block JSFunction::cast(isolate->global_context()->get(index)); 2689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Load its initial map. The global functions all have initial maps. 2699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Move(prototype, Handle<Map>(function->initial_map())); 2709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Load the prototype from the initial map. 2719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); 272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, 276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch, 278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* miss_label) { 279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the receiver isn't a smi. 280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(receiver, miss_label); 281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the object is a JS array. 283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); 284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, miss_label); 285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load length directly from the JS array. 287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, FieldOperand(receiver, JSArray::kLengthOffset)); 288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Generate code to check if an object is a string. If the object is 293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// a string, the map's instance type is left in the scratch register. 294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void GenerateStringCheck(MacroAssembler* masm, 295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register scratch, 297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* smi, 298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* non_string_object) { 299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the object isn't a smi. 300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(receiver, smi); 301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the object is a string. 303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); 304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movzxbq(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); 305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(kNotStringTag != 0); 306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ testl(scratch, Immediate(kNotStringTag)); 307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_zero, non_string_object); 308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, 312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 313402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Register scratch1, 314402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Register scratch2, 3151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label* miss, 3161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block bool support_wrappers) { 317402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Label check_wrapper; 318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the object is a string leaving the instance type in the 320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // scratch register. 3211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateStringCheck(masm, receiver, scratch1, miss, 3221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block support_wrappers ? &check_wrapper : miss); 323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load length directly from the string. 3256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rax, FieldOperand(receiver, String::kLengthOffset)); 326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (support_wrappers) { 3291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check if the object is a JSValue wrapper. 3301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&check_wrapper); 3311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ cmpl(scratch1, Immediate(JS_VALUE_TYPE)); 3321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ j(not_equal, miss); 333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check if the wrapped value is a string and load the length 3351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // directly if it is. 3361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); 3371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateStringCheck(masm, scratch2, scratch1, miss, miss); 3381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rax, FieldOperand(scratch2, String::kLengthOffset)); 3391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 3401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, 3459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register receiver, 3469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register result, 3479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch, 3489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label* miss_label) { 3499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ TryGetFunctionPrototype(receiver, result, miss_label); 3509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (!result.is(rax)) __ movq(rax, result); 3519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret(0); 3529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 3539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 3549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 3559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block// Load a fast property out of a holder object (src). In-object properties 3569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block// are loaded directly otherwise the property is loaded from the properties 3579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block// fixed array. 3589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, 3599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register dst, Register src, 3609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, int index) { 3619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Adjust for the number of properties stored in the holder. 3629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block index -= holder->map()->inobject_properties(); 3639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (index < 0) { 3649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the property straight out of the holder. 3659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block int offset = holder->map()->instance_size() + (index * kPointerSize); 3669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(dst, FieldOperand(src, offset)); 3679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { 3689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Calculate the offset into the properties array. 3699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block int offset = index * kPointerSize + FixedArray::kHeaderSize; 3709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset)); 3719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(dst, FieldOperand(dst, offset)); 3729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 3739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 3749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 3759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 3769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockstatic void PushInterceptorArguments(MacroAssembler* masm, 3779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register receiver, 3789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register holder, 3799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register name, 3809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder_obj) { 3819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(name); 3829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor(); 38344f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor)); 3849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Move(kScratchRegister, Handle<Object>(interceptor)); 3859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(kScratchRegister); 3869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(receiver); 3879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(holder); 3889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset)); 3899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 3909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 3919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm, 393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register holder, 395402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Register name, 396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block JSObject* holder_obj) { 397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block PushInterceptorArguments(masm, receiver, holder, name, holder_obj); 398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference ref = 40044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly), 40144f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()); 4028b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch __ Set(rax, 5); 40344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ LoadAddress(rbx, ref); 404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CEntryStub stub(1); 406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CallStub(&stub); 407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4108a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang// Number of pointers to be reserved on stack for fast API call. 4118a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wangstatic const int kFastApiCallArguments = 3; 412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 4148a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang// Reserves space for the extra arguments to API function in the 4156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// caller's frame. 4166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// 4176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// These arguments are set by CheckPrototypes and GenerateFastApiCall. 4186ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockstatic void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { 4196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------- S t a t e ------------- 4206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[0] : return address 4216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[8] : last argument in the internal frame of the caller 4226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------------------------------- 4236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(scratch, Operand(rsp, 0)); 4248a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); 4256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(Operand(rsp, 0), scratch); 4266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ Move(scratch, Smi::FromInt(0)); 4278a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang for (int i = 1; i <= kFastApiCallArguments; i++) { 4288a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ movq(Operand(rsp, i * kPointerSize), scratch); 4298a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang } 4306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 4316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 4326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 4336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// Undoes the effects of ReserveSpaceForFastApiCall. 4346ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockstatic void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { 4356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------- S t a t e ------------- 4368a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // -- rsp[0] : return address. 4378a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // -- rsp[8] : last fast api call extra argument. 4386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- ... 4398a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // -- rsp[kFastApiCallArguments * 8] : first fast api call extra argument. 4408a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal 4418a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // frame. 4426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------------------------------- 4436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(scratch, Operand(rsp, 0)); 4448a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ movq(Operand(rsp, kFastApiCallArguments * kPointerSize), scratch); 4458a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments)); 4466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 4476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 4486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 4498a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang// Generates call to API function. 4501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockstatic MaybeObject* GenerateFastApiCall(MacroAssembler* masm, 4511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block const CallOptimization& optimization, 4521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block int argc) { 4536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------- S t a t e ------------- 4546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[0] : return address 4556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- rsp[8] : object passing the type check 4566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // (last fast api call extra argument, 4576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // set by CheckPrototypes) 4588a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // -- rsp[16] : api function 4596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // (first fast api call extra argument) 4608a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // -- rsp[24] : api call data 4618a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // -- rsp[32] : last argument 4626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // -- ... 4638a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // -- rsp[(argc + 3) * 8] : first argument 4648a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // -- rsp[(argc + 4) * 8] : receiver 4656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // ----------------------------------- 4666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Get the function and setup the context. 4676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSFunction* function = optimization.constant_function(); 4686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ Move(rdi, Handle<JSFunction>(function)); 4696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); 4706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 4718a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // Pass the additional arguments. 4728a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ movq(Operand(rsp, 2 * kPointerSize), rdi); 4736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Object* call_data = optimization.api_call_info()->data(); 4748a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info()); 47544f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (masm->isolate()->heap()->InNewSpace(call_data)) { 4768a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ Move(rcx, api_call_info_handle); 4776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset)); 4788a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ movq(Operand(rsp, 3 * kPointerSize), rbx); 4796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } else { 4808a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ Move(Operand(rsp, 3 * kPointerSize), Handle<Object>(call_data)); 4816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 4826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 4838a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // Prepare arguments. 4848a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ lea(rbx, Operand(rsp, 3 * kPointerSize)); 4856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 4868a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang Object* callback = optimization.api_call_info()->callback(); 4878a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang Address api_function_address = v8::ToCData<Address>(callback); 4888a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang ApiFunction fun(api_function_address); 4898a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang 4908a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang#ifdef _WIN64 4918a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // Win64 uses first register--rcx--for returned value. 4928a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang Register arguments_arg = rdx; 4938a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang#else 4948a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang Register arguments_arg = rdi; 4958a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang#endif 4968a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang 4978a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // Allocate the v8::Arguments structure in the arguments' space since 4988a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // it's not controlled by GC. 4998a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang const int kApiStackSpace = 4; 5008a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang 5018a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ PrepareCallApiFunction(kApiStackSpace); 5028a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang 5038a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ movq(StackSpaceOperand(0), rbx); // v8::Arguments::implicit_args_. 5048a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ addq(rbx, Immediate(argc * kPointerSize)); 5058a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ movq(StackSpaceOperand(1), rbx); // v8::Arguments::values_. 5068a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ Set(StackSpaceOperand(2), argc); // v8::Arguments::length_. 5078a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // v8::Arguments::is_construct_call_. 5088a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ Set(StackSpaceOperand(3), 0); 5098a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang 5108a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // v8::InvocationCallback's argument. 5118a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang __ lea(arguments_arg, StackSpaceOperand(0)); 5128a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // Emitting a stub call may try to allocate (if the code is not 5138a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // already generated). Do not allow the assembler to perform a 5148a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // garbage collection but instead return the allocation failure 5158a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang // object. 5161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block return masm->TryCallApiFunctionAndReturn(&fun, 5171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block argc + kFastApiCallArguments + 1); 5186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 5196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass CallInterceptorCompiler BASE_EMBEDDED { 522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 5236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CallInterceptorCompiler(StubCompiler* stub_compiler, 5246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block const ParameterCount& arguments, 5256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register name) 5266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block : stub_compiler_(stub_compiler), 5276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block arguments_(arguments), 5286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block name_(name) {} 5296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block MaybeObject* Compile(MacroAssembler* masm, 5311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block JSObject* object, 5321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block JSObject* holder, 5331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block String* name, 5341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block LookupResult* lookup, 5351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register receiver, 5361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch1, 5371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch2, 5381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch3, 5391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label* miss) { 5406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ASSERT(holder->HasNamedInterceptor()); 5416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); 5426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Check that the receiver isn't a smi. 5446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ JumpIfSmi(receiver, miss); 5456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CallOptimization optimization(lookup); 5476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (optimization.is_constant_call()) { 5498a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang return CompileCacheable(masm, 5508a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang object, 5518a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang receiver, 5528a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang scratch1, 5538a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang scratch2, 5548a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang scratch3, 5558a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang holder, 5568a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang lookup, 5578a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang name, 5588a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang optimization, 5591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block miss); 5606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } else { 5616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CompileRegular(masm, 5626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block object, 5636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block receiver, 5646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block scratch1, 5656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block scratch2, 5663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch3, 5676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block name, 5686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block holder, 5696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block miss); 57044f0eee88ff00398ff7f715fab053374d808c90dSteve Block return masm->isolate()->heap()->undefined_value(); // Success. 5716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 5726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block private: 5751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block MaybeObject* CompileCacheable(MacroAssembler* masm, 5761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block JSObject* object, 5771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register receiver, 5781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch1, 5791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch2, 5801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch3, 5811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block JSObject* interceptor_holder, 5821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block LookupResult* lookup, 5831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block String* name, 5841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block const CallOptimization& optimization, 5851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label* miss_label) { 5866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ASSERT(optimization.is_constant_call()); 5876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ASSERT(!lookup->holder()->IsGlobalObject()); 5886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 5896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block int depth1 = kInvalidProtoDepth; 5906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block int depth2 = kInvalidProtoDepth; 5916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block bool can_do_fast_api_call = false; 5926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (optimization.is_simple_api_call() && 5936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block !lookup->holder()->IsGlobalObject()) { 594f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke depth1 = 595f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke optimization.GetPrototypeDepthOfExpectedType(object, 596f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke interceptor_holder); 5976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (depth1 == kInvalidProtoDepth) { 598f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke depth2 = 599f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke optimization.GetPrototypeDepthOfExpectedType(interceptor_holder, 600f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke lookup->holder()); 601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 6026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || 6036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block (depth2 != kInvalidProtoDepth); 604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 60644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = masm->isolate()->counters(); 60744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->call_const_interceptor(), 1); 608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (can_do_fast_api_call) { 61044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1); 6116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ReserveSpaceForFastApiCall(masm, scratch1); 6126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 613402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 614f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // Check that the maps from receiver to interceptor's holder 615f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // haven't changed and thus we can invoke interceptor. 6166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label miss_cleanup; 6176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; 6186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register holder = 6197f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch stub_compiler_->CheckPrototypes(object, receiver, 6207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch interceptor_holder, scratch1, 6213bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch2, scratch3, name, depth1, miss); 622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 623f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // Invoke an interceptor and if it provides a value, 624f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // branch to |regular_invoke|. 6256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label regular_invoke; 626f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke LoadWithInterceptor(masm, receiver, holder, interceptor_holder, 627f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke ®ular_invoke); 628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 629f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // Interceptor returned nothing for this property. Try to use cached 630f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // constant function. 631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 632f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // Check that the maps from interceptor's holder to constant function's 633f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // holder haven't changed and thus we can use cached constant function. 6347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch if (interceptor_holder != lookup->holder()) { 6357f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch stub_compiler_->CheckPrototypes(interceptor_holder, receiver, 6367f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch lookup->holder(), scratch1, 6373bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch2, scratch3, name, depth2, miss); 6387f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } else { 6397f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // CheckPrototypes has a side effect of fetching a 'holder' 6407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // for API (object which is instanceof for the signature). It's 6417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // safe to omit it here, as if present, it should be fetched 6427f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch // by the previous CheckPrototypes. 6437f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch ASSERT(depth2 == kInvalidProtoDepth); 6447f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } 645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 646f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // Invoke function. 6476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (can_do_fast_api_call) { 6481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block MaybeObject* result = GenerateFastApiCall(masm, 6491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block optimization, 6501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block arguments_.immediate()); 6511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (result->IsFailure()) return result; 6526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } else { 6536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ InvokeFunction(optimization.constant_function(), arguments_, 6546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JUMP_FUNCTION); 6556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 657f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // Deferred code for fast API call case---clean preallocated space. 6586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (can_do_fast_api_call) { 6596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ bind(&miss_cleanup); 6606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block FreeSpaceForFastApiCall(masm, scratch1); 6616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ jmp(miss_label); 6626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 664f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // Invoke a regular function. 6656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ bind(®ular_invoke); 6666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (can_do_fast_api_call) { 6676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block FreeSpaceForFastApiCall(masm, scratch1); 6686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 6698a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang 67044f0eee88ff00398ff7f715fab053374d808c90dSteve Block return masm->isolate()->heap()->undefined_value(); // Success. 671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block void CompileRegular(MacroAssembler* masm, 6746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSObject* object, 675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Register receiver, 6766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register scratch1, 6776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register scratch2, 6783bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch Register scratch3, 6796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block String* name, 680f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke JSObject* interceptor_holder, 681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label* miss_label) { 6826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register holder = 683f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, 6843bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch scratch1, scratch2, scratch3, name, 6856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block miss_label); 6866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ EnterInternalFrame(); 688402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Save the name_ register across the call. 689402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ push(name_); 690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block PushInterceptorArguments(masm, 692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block receiver, 693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block holder, 694402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu name_, 695f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke interceptor_holder); 696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 697402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ CallExternalReference( 69844f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall), 69944f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()), 700402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu 5); 701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Restore the name_ register. 703402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu __ pop(name_); 704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ LeaveInternalFrame(); 705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block void LoadWithInterceptor(MacroAssembler* masm, 7086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register receiver, 7096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Register holder, 7106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSObject* holder_obj, 7116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Label* interceptor_succeeded) { 7126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ EnterInternalFrame(); 7136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ push(holder); // Save the holder. 7146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ push(name_); // Save the name. 7156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 7166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CompileCallLoadPropertyWithInterceptor(masm, 7176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block receiver, 7186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block holder, 7196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block name_, 7206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block holder_obj); 7216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 7226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ pop(name_); // Restore the name. 7236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ pop(receiver); // Restore the holder. 7246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ LeaveInternalFrame(); 7256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 7266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); 7276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ j(not_equal, interceptor_succeeded); 7286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 7296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 7306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block StubCompiler* stub_compiler_; 731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const ParameterCount& arguments_; 732402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu Register name_; 733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { 7379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); 7389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Code* code = NULL; 7399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (kind == Code::LOAD_IC) { 74044f0eee88ff00398ff7f715fab053374d808c90dSteve Block code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss); 7419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { 74244f0eee88ff00398ff7f715fab053374d808c90dSteve Block code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss); 7439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 7449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 7459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Handle<Code> ic(code); 7469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Jump(ic, RelocInfo::CODE_TARGET); 7479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 7489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 7499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 7509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block// Both name_reg and receiver_reg are preserved on jumps to miss_label, 7519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block// but may be destroyed if store is successful. 7529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateStoreField(MacroAssembler* masm, 7539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* object, 7549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block int index, 7559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Map* transition, 7569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register receiver_reg, 7579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register name_reg, 7589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch, 7599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label* miss_label) { 7609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the object isn't a smi. 7619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(receiver_reg, miss_label); 7629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 7639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the map of the object hasn't changed. 7649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset), 7659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Handle<Map>(object->map())); 7669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, miss_label); 7679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 7689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Perform global security token check if needed. 7699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (object->IsJSGlobalProxy()) { 7709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label); 7719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 7729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 7739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Stub never generated for non-global objects that require access 7749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // checks. 7759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); 7769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 7779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Perform map transition for the receiver if necessary. 7789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) { 7799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // The properties must be extended before we can store the value. 7809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // We jump to a runtime call that extends the properties array. 7819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ pop(scratch); // Return address. 7829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(receiver_reg); 7839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Push(Handle<Map>(transition)); 7849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(rax); 7859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(scratch); 7869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ TailCallExternalReference( 78744f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), 78844f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()), 78944f0eee88ff00398ff7f715fab053374d808c90dSteve Block 3, 79044f0eee88ff00398ff7f715fab053374d808c90dSteve Block 1); 7919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return; 7929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 7939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 7949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (transition != NULL) { 7959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Update the map of the object; no write barrier updating is 7969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // needed because the map is never in new space. 7979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset), 7989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Handle<Map>(transition)); 7999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 8009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 8019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Adjust for the number of properties stored in the object. Even in the 8029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // face of a transition we can use the old map here because the size of the 8039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // object and the number of in-object properties is not going to change. 8049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block index -= object->map()->inobject_properties(); 8059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 8069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (index < 0) { 8079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Set the property straight into the object. 8089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block int offset = object->map()->instance_size() + (index * kPointerSize); 8099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(FieldOperand(receiver_reg, offset), rax); 8109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 8119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Update the write barrier for the array address. 8129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Pass the value being stored in the now unused name_reg. 8139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(name_reg, rax); 8149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ RecordWrite(receiver_reg, offset, name_reg, scratch); 8159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { 8169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Write to the properties array. 8179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block int offset = index * kPointerSize + FixedArray::kHeaderSize; 8189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the properties array (optimistically). 8199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); 8209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(FieldOperand(scratch, offset), rax); 8219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 8229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Update the write barrier for the array address. 8239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Pass the value being stored in the now unused name_reg. 8249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(name_reg, rax); 8259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ RecordWrite(scratch, offset, name_reg, receiver_reg); 8269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 8279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 8289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the value (register rax). 8299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret(0); 8309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 8319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 8329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 8339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block// Generate code to check that a global property cell is empty. Create 8349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block// the property cell at compilation time if no cell exists for the 8356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// property. 8365913587db4c6bab03d97bfe44b06289fd6d7270dJohn ReckMUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell( 8375913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck MacroAssembler* masm, 8385913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck GlobalObject* global, 8395913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck String* name, 8405913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck Register scratch, 8415913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck Label* miss) { 8425913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck Object* probe; 8435913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck { MaybeObject* maybe_probe = global->EnsurePropertyCell(name); 8445913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck if (!maybe_probe->ToObject(&probe)) return maybe_probe; 8455913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck } 8466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); 8476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block ASSERT(cell->value()->IsTheHole()); 8486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ Move(scratch, Handle<Object>(cell)); 8496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), 85044f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm->isolate()->factory()->the_hole_value()); 8516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ j(not_equal, miss); 8526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block return cell; 8536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 8546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 8556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __ 857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM((masm())) 858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 8599dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 8609fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockRegister StubCompiler::CheckPrototypes(JSObject* object, 8619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register object_reg, 8629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 8639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register holder_reg, 8649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch1, 8659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch2, 8669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name, 8679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block int save_at_depth, 8689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label* miss) { 8699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Make sure there's no overlap between holder and object registers. 8709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); 8719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) 8729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block && !scratch2.is(scratch1)); 8739dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 8749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Keep track of the current object in register reg. On the first 8759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // iteration, reg is an alias for object_reg, on later iterations, 8769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // it is an alias for holder_reg. 8779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register reg = object_reg; 8789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block int depth = 0; 8799dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 8809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (save_at_depth == depth) { 8819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(Operand(rsp, kPointerSize), object_reg); 8829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 88359151504615d929945dc59db37bf1166937748c6Steve Block 8849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check the maps in the prototype chain. 8859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Traverse the prototype chain from the object and do map checks. 8869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* current = object; 8879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block while (current != holder) { 8889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block depth++; 88959151504615d929945dc59db37bf1166937748c6Steve Block 8909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Only global objects and objects that do not require access 8919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // checks are allowed in stubs. 8929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); 89359151504615d929945dc59db37bf1166937748c6Steve Block 8949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* prototype = JSObject::cast(current->GetPrototype()); 8959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (!current->HasFastProperties() && 8969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block !current->IsJSGlobalObject() && 8979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block !current->IsJSGlobalProxy()) { 8989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (!name->IsSymbol()) { 89944f0eee88ff00398ff7f715fab053374d808c90dSteve Block MaybeObject* lookup_result = heap()->LookupSymbol(name); 9009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (lookup_result->IsFailure()) { 9019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block set_failure(Failure::cast(lookup_result)); 9029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return reg; 9039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { 9049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block name = String::cast(lookup_result->ToObjectUnchecked()); 9059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 9069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 9079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(current->property_dictionary()->FindEntry(name) == 9089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block StringDictionary::kNotFound); 90959151504615d929945dc59db37bf1166937748c6Steve Block 9109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateDictionaryNegativeLookup(masm(), 9119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block miss, 9129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block reg, 9139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block name, 9149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block scratch1, 9159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block scratch2); 9169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); 9179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block reg = holder_reg; // from now the object is in holder_reg 9189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); 91944f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else if (heap()->InNewSpace(prototype)) { 9209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the map of the current object. 9219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); 9229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(scratch1, Handle<Map>(current->map())); 9239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Branch on the result of the map check. 9249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, miss); 9259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check access rights to the global object. This has to happen 9269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // after the map check so that we know that the object is 9279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // actually a global object. 9289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (current->IsJSGlobalProxy()) { 9299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CheckAccessGlobalProxy(reg, scratch1, miss); 93059151504615d929945dc59db37bf1166937748c6Steve Block 9319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Restore scratch register to be the map of the object. 9329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // We load the prototype from the map in the scratch register. 9339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); 9349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 9359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // The prototype is in new space; we cannot store a reference 9369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // to it in the code. Load it from the map. 9379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block reg = holder_reg; // from now the object is in holder_reg 9389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); 93959151504615d929945dc59db37bf1166937748c6Steve Block 9409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { 9419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check the map of the current object. 9429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), 9439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Handle<Map>(current->map())); 9449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Branch on the result of the map check. 9459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, miss); 9469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check access rights to the global object. This has to happen 9479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // after the map check so that we know that the object is 9489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // actually a global object. 9499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (current->IsJSGlobalProxy()) { 9509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CheckAccessGlobalProxy(reg, scratch1, miss); 9519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 9529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // The prototype is in old space; load it directly. 9539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block reg = holder_reg; // from now the object is in holder_reg 9549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Move(reg, Handle<JSObject>(prototype)); 9559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 95659151504615d929945dc59db37bf1166937748c6Steve Block 9579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (save_at_depth == depth) { 9589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(Operand(rsp, kPointerSize), reg); 9599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 96059151504615d929945dc59db37bf1166937748c6Steve Block 9619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Go to the next object in the prototype chain. 9629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block current = prototype; 96359151504615d929945dc59db37bf1166937748c6Steve Block } 96459151504615d929945dc59db37bf1166937748c6Steve Block 9659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check the holder map. 9669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), Handle<Map>(holder->map())); 9679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, miss); 96859151504615d929945dc59db37bf1166937748c6Steve Block 9699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Log the check depth. 97044f0eee88ff00398ff7f715fab053374d808c90dSteve Block LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); 9717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 9729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Perform security check for access to the global object and return 9739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // the holder register. 9749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(current == holder); 9759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); 9769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (current->IsJSGlobalProxy()) { 9779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CheckAccessGlobalProxy(reg, scratch1, miss); 978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 9809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // If we've skipped any global objects, it's not enough to verify 9819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // that their maps haven't changed. We also need to check that the 9829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // property cell for the property is still empty. 9839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block current = object; 9849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block while (current != holder) { 9859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (current->IsGlobalObject()) { 9869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block MaybeObject* cell = GenerateCheckPropertyCell(masm(), 9879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GlobalObject::cast(current), 9889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block name, 9899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block scratch1, 9909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block miss); 9919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (cell->IsFailure()) { 9929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block set_failure(Failure::cast(cell)); 9939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return reg; 994e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke } 9958a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang } 9969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block current = JSObject::cast(current->GetPrototype()); 9975913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck } 998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 9999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the register containing the holder. 10009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return reg; 1001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 10049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateLoadField(JSObject* object, 10059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 10069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register receiver, 10079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch1, 10089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch2, 10099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch3, 10109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block int index, 10119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name, 10129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label* miss) { 1013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the receiver isn't a smi. 10149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(receiver, miss); 1015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 10169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check the prototype chain. 10179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register reg = 10189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(object, receiver, holder, 10199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block scratch1, scratch2, scratch3, name, miss); 1020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 10219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the value from the properties. 10229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateFastPropertyLoad(masm(), rax, reg, holder, index); 10239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret(0); 1024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 10271e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockMaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, 10281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block JSObject* holder, 10291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register receiver, 10301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register name_reg, 10311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch1, 10321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch2, 10331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Register scratch3, 10341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block AccessorInfo* callback, 10351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block String* name, 10361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label* miss) { 10379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the receiver isn't a smi. 10389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(receiver, miss); 10396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 10409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the maps haven't changed. 10419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register reg = 10429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(object, receiver, holder, scratch1, 10439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block scratch2, scratch3, name, miss); 10446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 10459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Handle<AccessorInfo> callback_handle(callback); 10466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 10479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Insert additional parameters into the stack frame above return address. 10489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(!scratch2.is(reg)); 10499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ pop(scratch2); // Get return address to place it below. 10509dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 10519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(receiver); // receiver 10529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(reg); // holder 105344f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (heap()->InNewSpace(callback_handle->data())) { 10549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Move(scratch1, callback_handle); 10559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); // data 10569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { 10579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Push(Handle<Object>(callback_handle->data())); 10589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 10599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(name_reg); // name 10609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Save a pointer to where we pushed the arguments pointer. 10619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // This will be passed as the const AccessorInfo& to the C++ callback. 10626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 10639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block#ifdef _WIN64 10649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Win64 uses first register--rcx--for returned value. 10659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register accessor_info_arg = r8; 10669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register name_arg = rdx; 10679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block#else 10689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register accessor_info_arg = rsi; 10699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register name_arg = rdi; 10709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block#endif 10716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 10729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(!name_arg.is(scratch2)); 10739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(name_arg, rsp); 10749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(scratch2); // Restore return address. 10756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 10769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Do call through the api. 10779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Address getter_address = v8::ToCData<Address>(callback->getter()); 10789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ApiFunction fun(getter_address); 1079756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick 10809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // 3 elements array for v8::Agruments::values_ and handler for name. 10819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const int kStackSpace = 4; 10826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 10839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Allocate v8::AccessorInfo in non-GCed stack space. 10849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const int kArgStackSpace = 1; 10856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 10869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ PrepareCallApiFunction(kArgStackSpace); 10879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ lea(rax, Operand(name_arg, 3 * kPointerSize)); 10886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 10899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // v8::AccessorInfo::args_. 10909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(StackSpaceOperand(0), rax); 10916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 10929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // The context register (rsi) has been saved in PrepareCallApiFunction and 10939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // could be used to pass arguments. 10949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ lea(accessor_info_arg, StackSpaceOperand(0)); 10956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 10969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Emitting a stub call may try to allocate (if the code is not 10979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // already generated). Do not allow the assembler to perform a 10989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // garbage collection but instead return the allocation failure 10999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // object. 11001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); 11019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 11026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateLoadConstant(JSObject* object, 11059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 11069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register receiver, 11079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch1, 11089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch2, 11099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch3, 11109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Object* value, 11119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name, 11129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label* miss) { 11139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the receiver isn't a smi. 11149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(receiver, miss); 11156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the maps haven't changed. 11179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register reg = 11189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(object, receiver, holder, 11199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block scratch1, scratch2, scratch3, name, miss); 11209dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 11219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the constant value. 11229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Move(rax, Handle<Object>(value)); 11239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret(0); 11249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 11256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid StubCompiler::GenerateLoadInterceptor(JSObject* object, 11289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* interceptor_holder, 11299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block LookupResult* lookup, 11309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register receiver, 11319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register name_reg, 11329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch1, 11339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch2, 11349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch3, 11359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name, 11369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label* miss) { 11379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(interceptor_holder->HasNamedInterceptor()); 11389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); 11396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the receiver isn't a smi. 11419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(receiver, miss); 11426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // So far the most popular follow ups for interceptor loads are FIELD 11449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // and CALLBACKS, so inline only them, other cases may be added 11459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // later. 11469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block bool compile_followup_inline = false; 11479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (lookup->IsProperty() && lookup->IsCacheable()) { 11489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (lookup->type() == FIELD) { 11499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block compile_followup_inline = true; 11509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else if (lookup->type() == CALLBACKS && 11519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block lookup->GetCallbackObject()->IsAccessorInfo() && 11529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) { 11539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block compile_followup_inline = true; 11549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 11559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 11569dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 11579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (compile_followup_inline) { 11589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Compile the interceptor call, followed by inline code to load the 11599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // property from further up the prototype chain if the call fails. 11609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the maps haven't changed. 11619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, 11629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block scratch1, scratch2, scratch3, 11639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block name, miss); 11649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); 11656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Save necessary data before invoking an interceptor. 11679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Requires a frame to make GC aware of pushed pointers. 11689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ EnterInternalFrame(); 11695913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck 11709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { 11719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // CALLBACKS case needs a receiver to be passed into C++ callback. 11729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(receiver); 11739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 11749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(holder_reg); 11759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(name_reg); 11766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Invoke an interceptor. Note: map checks from receiver to 11789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // interceptor's holder has been compiled before (see a caller 11799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // of this method.) 11809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CompileCallLoadPropertyWithInterceptor(masm(), 11819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block receiver, 11829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block holder_reg, 11839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block name_reg, 11849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block interceptor_holder); 11856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check if interceptor provided a value for property. If it's 11879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // the case, return immediately. 11889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label interceptor_failed; 11899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); 11909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(equal, &interceptor_failed); 11919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ LeaveInternalFrame(); 11929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret(0); 11936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 11949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&interceptor_failed); 11959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ pop(name_reg); 11969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ pop(holder_reg); 11979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { 11989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ pop(receiver); 11999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 12006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ LeaveInternalFrame(); 12026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the maps from interceptor's holder to lookup's holder 12049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // haven't changed. And load lookup's holder into |holder| register. 12059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (interceptor_holder != lookup->holder()) { 12069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block holder_reg = CheckPrototypes(interceptor_holder, 12079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block holder_reg, 12089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block lookup->holder(), 12099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block scratch1, 12109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block scratch2, 12119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block scratch3, 12129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block name, 12139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block miss); 12149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 12156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (lookup->type() == FIELD) { 12179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // We found FIELD property in prototype chain of interceptor's holder. 12189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Retrieve a field from field's holder. 12199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateFastPropertyLoad(masm(), rax, holder_reg, 12209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block lookup->holder(), lookup->GetFieldIndex()); 12219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret(0); 12229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { 12239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // We found CALLBACKS property in prototype chain of interceptor's 12249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // holder. 12259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(lookup->type() == CALLBACKS); 12269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); 12279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); 12289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(callback != NULL); 12299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(callback->getter() != NULL); 1230756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick 12319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Tail call to runtime. 12329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Important invariant in CALLBACKS case: the code above must be 12339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // structured to never clobber |receiver| register. 12349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ pop(scratch2); // return address 12359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(receiver); 12369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(holder_reg); 12379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Move(holder_reg, Handle<AccessorInfo>(callback)); 12389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset)); 12399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(holder_reg); 12409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(name_reg); 12419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(scratch2); // restore return address 1242756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick 12439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ExternalReference ref = 124444f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference(IC_Utility(IC::kLoadCallbackProperty), 124544f0eee88ff00398ff7f715fab053374d808c90dSteve Block isolate()); 12469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ TailCallExternalReference(ref, 5, 1); 12476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block } 12489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { // !compile_followup_inline 12499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Call the runtime system to load the interceptor. 12509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the maps haven't changed. 12519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, 12529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block scratch1, scratch2, scratch3, 12539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block name, miss); 12549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ pop(scratch2); // save old return address 12559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block PushInterceptorArguments(masm(), receiver, holder_reg, 12569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block name_reg, interceptor_holder); 12579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(scratch2); // restore old return address 12586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ExternalReference ref = ExternalReference( 126044f0eee88ff00398ff7f715fab053374d808c90dSteve Block IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate()); 12619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ TailCallExternalReference(ref, 5, 1); 12625913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck } 12636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 12646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { 12679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (kind_ == Code::KEYED_CALL_IC) { 12689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(rcx, Handle<String>(name)); 12699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, miss); 12709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 12719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 12726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object, 12759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 12769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name, 12779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label* miss) { 12789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(holder->IsGlobalObject()); 12796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the number of arguments. 12819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const int argc = arguments().immediate(); 12829dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 12836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Get the receiver from the stack. 12846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 12856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // If the object is the holder then we know that it's a global 12879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // object which can only happen for contextual calls. In this case, 12889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // the receiver cannot be a smi. 12899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (object != holder) { 12909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(rdx, miss); 12915913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck } 12926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the maps haven't changed. 12949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(object, rdx, holder, rbx, rax, rdi, name, miss); 12956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 12966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 12989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, 12999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSFunction* function, 13009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label* miss) { 13019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the value from the cell. 13029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Move(rdi, Handle<JSGlobalPropertyCell>(cell)); 13039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset)); 130480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 13059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the cell contains the same function. 130644f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (heap()->InNewSpace(function)) { 13079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // We can't embed a pointer to a function in new space so we have 13089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // to verify that the shared function info is unchanged. This has 13099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // the nice side effect that multiple closures based on the same 13109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // function can all use this call IC. Before we load through the 13119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // function, we have to verify that it still is a function. 13129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(rdi, miss); 13139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax); 13149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, miss); 131580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 13169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check the shared function info. Make sure it hasn't changed. 13179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Move(rax, Handle<SharedFunctionInfo>(function->shared())); 13189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax); 13199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, miss); 132080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } else { 13219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(rdi, Handle<JSFunction>(function)); 13229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, miss); 132380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen } 13249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 132580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 132680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 13279fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::GenerateMissBranch() { 132844f0eee88ff00398ff7f715fab053374d808c90dSteve Block MaybeObject* maybe_obj = isolate()->stub_cache()->ComputeCallMiss( 132944f0eee88ff00398ff7f715fab053374d808c90dSteve Block arguments().immediate(), kind_); 13305913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck Object* obj; 13319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (!maybe_obj->ToObject(&obj)) return maybe_obj; 13329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); 13339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return obj; 13347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch} 13357f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 13367f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 13379fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileCallField(JSObject* object, 13389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 13399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block int index, 13409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 134180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ----------- S t a t e ------------- 13429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rcx : function name 13439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[0] : return address 13449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[8] : argument argc 13459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[16] : argument argc - 1 13469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ... 13479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[argc * 8] : argument 1 13489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[(argc + 1) * 8] : argument 0 = receiver 134980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // ----------------------------------- 135080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen Label miss; 13519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 135280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen GenerateNameCheck(name, &miss); 135380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 13549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the receiver from the stack. 13559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const int argc = arguments().immediate(); 13569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 135780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 13589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the receiver isn't a smi. 13599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(rdx, &miss); 136080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 13619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Do the right check and compute the holder register. 13629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register reg = CheckPrototypes(object, rdx, holder, rbx, rax, rdi, 13639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block name, &miss); 136480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 13659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateFastPropertyLoad(masm(), rdi, reg, holder, index); 136680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 13679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the function really is a function. 13689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(rdi, &miss); 13699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rbx); 13709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &miss); 13719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 13729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Patch the receiver on the stack with the global proxy if 13739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // necessary. 13749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (object->IsGlobalObject()) { 13759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); 13769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); 13779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 13789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 13799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Invoke the function. 13809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION); 13817f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 13829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Handle call cache miss. 138380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen __ bind(&miss); 138444f0eee88ff00398ff7f715fab053374d808c90dSteve Block MaybeObject* maybe_result = GenerateMissBranch(); 138544f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (maybe_result->IsFailure()) return maybe_result; 138680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen 138780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen // Return the generated code. 13889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(FIELD, name); 138980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} 13906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 13916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 13929fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, 13939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 13949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSGlobalPropertyCell* cell, 13959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSFunction* function, 13969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 139759151504615d929945dc59db37bf1166937748c6Steve Block // ----------- S t a t e ------------- 13989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rcx : name 139959151504615d929945dc59db37bf1166937748c6Steve Block // -- rsp[0] : return address 140059151504615d929945dc59db37bf1166937748c6Steve Block // -- rsp[(argc - n) * 8] : arg[n] (zero-based) 140159151504615d929945dc59db37bf1166937748c6Steve Block // -- ... 140259151504615d929945dc59db37bf1166937748c6Steve Block // -- rsp[(argc + 1) * 8] : receiver 140359151504615d929945dc59db37bf1166937748c6Steve Block // ----------------------------------- 140459151504615d929945dc59db37bf1166937748c6Steve Block 14059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // If object is not an array, bail out to regular call. 140644f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value(); 140759151504615d929945dc59db37bf1166937748c6Steve Block 140859151504615d929945dc59db37bf1166937748c6Steve Block Label miss; 14099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 141059151504615d929945dc59db37bf1166937748c6Steve Block GenerateNameCheck(name, &miss); 141159151504615d929945dc59db37bf1166937748c6Steve Block 14129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the receiver from the stack. 14139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const int argc = arguments().immediate(); 14149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 141559151504615d929945dc59db37bf1166937748c6Steve Block 14169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the receiver isn't a smi. 14179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(rdx, &miss); 141859151504615d929945dc59db37bf1166937748c6Steve Block 14199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(JSObject::cast(object), 14209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rdx, 14219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block holder, 14229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rbx, 14239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rax, 14249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rdi, 14259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block name, 14269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &miss); 14279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 14289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (argc == 0) { 14299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Noop, return the length. 14309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset)); 14319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret((argc + 1) * kPointerSize); 143259151504615d929945dc59db37bf1166937748c6Steve Block } else { 14339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label call_builtin; 143459151504615d929945dc59db37bf1166937748c6Steve Block 14359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the elements array of the object. 14369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset)); 143759151504615d929945dc59db37bf1166937748c6Steve Block 14389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the elements are in fast mode and writable. 14399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), 144044f0eee88ff00398ff7f715fab053374d808c90dSteve Block factory()->fixed_array_map()); 14419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &call_builtin); 144259151504615d929945dc59db37bf1166937748c6Steve Block 14439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (argc == 1) { // Otherwise fall through to call builtin. 14449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label exit, with_write_barrier, attempt_to_grow_elements; 144559151504615d929945dc59db37bf1166937748c6Steve Block 14469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the array's length into rax and calculate new length. 14479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset)); 14489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue); 14499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ addl(rax, Immediate(argc)); 145059151504615d929945dc59db37bf1166937748c6Steve Block 14519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the element's length into rcx. 14529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ SmiToInteger32(rcx, FieldOperand(rbx, FixedArray::kLengthOffset)); 145359151504615d929945dc59db37bf1166937748c6Steve Block 14549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check if we could survive without allocation. 14559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ cmpl(rax, rcx); 14569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(greater, &attempt_to_grow_elements); 14579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 14589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Save new length. 14599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax); 14609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 14619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Push the element. 14629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rcx, Operand(rsp, argc * kPointerSize)); 14639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ lea(rdx, FieldOperand(rbx, 14649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rax, times_pointer_size, 14659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block FixedArray::kHeaderSize - argc * kPointerSize)); 14669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(Operand(rdx, 0), rcx); 14679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 14689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check if value is a smi. 14699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Integer32ToSmi(rax, rax); // Return new length as smi. 14709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 14719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfNotSmi(rcx, &with_write_barrier); 14729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 14739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&exit); 14749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret((argc + 1) * kPointerSize); 14759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 14769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&with_write_barrier); 14779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 14789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ InNewSpace(rbx, rcx, equal, &exit); 14799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 14809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ RecordWriteHelper(rbx, rdx, rcx); 14819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 14829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret((argc + 1) * kPointerSize); 14839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 14849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&attempt_to_grow_elements); 14859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (!FLAG_inline_new) { 14869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ jmp(&call_builtin); 14879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 14889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 14899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ExternalReference new_space_allocation_top = 149044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::new_space_allocation_top_address(isolate()); 14919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ExternalReference new_space_allocation_limit = 149244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference::new_space_allocation_limit_address(isolate()); 14939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 14949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const int kAllocationDelta = 4; 14959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Load top. 149644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Load(rcx, new_space_allocation_top); 14979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 14989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check if it's the end of elements. 14999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ lea(rdx, FieldOperand(rbx, 15009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rax, times_pointer_size, 15019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block FixedArray::kHeaderSize - argc * kPointerSize)); 15029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ cmpq(rdx, rcx); 15039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &call_builtin); 15049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ addq(rcx, Immediate(kAllocationDelta * kPointerSize)); 150544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Operand limit_operand = 150644f0eee88ff00398ff7f715fab053374d808c90dSteve Block masm()->ExternalOperand(new_space_allocation_limit); 150744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cmpq(rcx, limit_operand); 15089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(above, &call_builtin); 15099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 15109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // We fit and could grow elements. 151144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Store(new_space_allocation_top, rcx); 15129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rcx, Operand(rsp, argc * kPointerSize)); 15139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 15149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Push the argument... 15159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(Operand(rdx, 0), rcx); 15169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ... and fill the rest with holes. 15179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); 15189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block for (int i = 1; i < kAllocationDelta; i++) { 15199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(Operand(rdx, i * kPointerSize), kScratchRegister); 15209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 15219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 15229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Restore receiver to rdx as finish sequence assumes it's here. 15239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 15249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 15259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Increment element's and array's sizes. 15269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ SmiAddConstant(FieldOperand(rbx, FixedArray::kLengthOffset), 15279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Smi::FromInt(kAllocationDelta)); 15289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 15299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Make new length a smi before returning it. 15309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Integer32ToSmi(rax, rax); 15319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax); 15329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 15339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Elements are in new space, so write barrier is not required. 15349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret((argc + 1) * kPointerSize); 15359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 15369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 15379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&call_builtin); 153844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush, 153944f0eee88ff00398ff7f715fab053374d808c90dSteve Block isolate()), 15409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block argc + 1, 15419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 1); 15429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 154359151504615d929945dc59db37bf1166937748c6Steve Block 154459151504615d929945dc59db37bf1166937748c6Steve Block __ bind(&miss); 154544f0eee88ff00398ff7f715fab053374d808c90dSteve Block MaybeObject* maybe_result = GenerateMissBranch(); 154644f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (maybe_result->IsFailure()) return maybe_result; 154759151504615d929945dc59db37bf1166937748c6Steve Block 154859151504615d929945dc59db37bf1166937748c6Steve Block // Return the generated code. 15499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(function); 15500d5e116f6aee03185f237311a943491bb079a768Kristian Monsen} 15510d5e116f6aee03185f237311a943491bb079a768Kristian Monsen 15520d5e116f6aee03185f237311a943491bb079a768Kristian Monsen 15539fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object, 15549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 15559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSGlobalPropertyCell* cell, 15569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSFunction* function, 15579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 1558f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // ----------- S t a t e ------------- 15599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rcx : name 1560f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // -- rsp[0] : return address 1561f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // -- rsp[(argc - n) * 8] : arg[n] (zero-based) 1562f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // -- ... 1563f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // -- rsp[(argc + 1) * 8] : receiver 1564f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // ----------------------------------- 1565f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 15669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // If object is not an array, bail out to regular call. 156744f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value(); 1568f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 15699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss, return_undefined, call_builtin; 1570f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 1571f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch GenerateNameCheck(name, &miss); 1572f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 15739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the receiver from the stack. 15749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const int argc = arguments().immediate(); 15759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 1576f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 15779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the receiver isn't a smi. 15789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(rdx, &miss); 1579f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 15809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(JSObject::cast(object), rdx, 15819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block holder, rbx, 15829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rax, rdi, name, &miss); 1583f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 15849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the elements array of the object. 15859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset)); 1586f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 15879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the elements are in fast mode and writable. 15889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), 15899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Heap::kFixedArrayMapRootIndex); 15909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &call_builtin); 1591f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 15929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the array's length into rcx and calculate new length. 15939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ SmiToInteger32(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); 15949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ subl(rcx, Immediate(1)); 15959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(negative, &return_undefined); 1596f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 15979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the last element. 15989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ LoadRoot(r9, Heap::kTheHoleValueRootIndex); 15999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rax, FieldOperand(rbx, 16009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rcx, times_pointer_size, 16019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block FixedArray::kHeaderSize)); 16029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check if element is already the hole. 16039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ cmpq(rax, r9); 16049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // If so, call slow-case to also check prototypes for value. 16059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(equal, &call_builtin); 1606f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 16079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Set the array's length. 16089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rcx); 1609f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 16109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Fill with the hole and return original value. 16119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(FieldOperand(rbx, 16129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rcx, times_pointer_size, 16139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block FixedArray::kHeaderSize), 16149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block r9); 16159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret((argc + 1) * kPointerSize); 1616f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 16179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&return_undefined); 16189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); 16199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret((argc + 1) * kPointerSize); 1620f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 16219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&call_builtin); 162244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ TailCallExternalReference( 162344f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference(Builtins::c_ArrayPop, isolate()), 162444f0eee88ff00398ff7f715fab053374d808c90dSteve Block argc + 1, 162544f0eee88ff00398ff7f715fab053374d808c90dSteve Block 1); 1626f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 1627f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch __ bind(&miss); 162844f0eee88ff00398ff7f715fab053374d808c90dSteve Block MaybeObject* maybe_result = GenerateMissBranch(); 162944f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (maybe_result->IsFailure()) return maybe_result; 1630f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 1631f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // Return the generated code. 16329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(function); 1633f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch} 1634f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 1635f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 16369fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( 16379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Object* object, 16389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 16399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSGlobalPropertyCell* cell, 16409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSFunction* function, 16419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 1642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 16439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rcx : function name 16449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 16459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[(argc - n) * 8] : arg[n] (zero-based) 16469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- ... 16479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[(argc + 1) * 8] : receiver 1648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 1649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 16509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // If object is not a string, bail out to regular call. 165144f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!object->IsString() || cell != NULL) return heap()->undefined_value(); 16529dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 1653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const int argc = arguments().immediate(); 1654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 16559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 1656b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch Label name_miss; 16579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label index_out_of_range; 1658b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch Label* index_out_of_range_label = &index_out_of_range; 1659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1660b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { 1661b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch index_out_of_range_label = &miss; 1662b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } 1663b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch 1664b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch GenerateNameCheck(name, &name_miss); 1665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 16669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the maps starting from the prototype haven't changed. 16679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateDirectLoadGlobalFunctionPrototype(masm(), 16689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Context::STRING_FUNCTION_INDEX, 16699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rax, 16709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &miss); 16719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(object != holder); 16729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 16739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rbx, rdx, rdi, name, &miss); 1674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 16759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register receiver = rbx; 16769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register index = rdi; 16779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch = rdx; 16789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register result = rax; 16799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); 16809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (argc > 0) { 16819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(index, Operand(rsp, (argc - 0) * kPointerSize)); 16829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { 16839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ LoadRoot(index, Heap::kUndefinedValueRootIndex); 16849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 1685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 16869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block StringCharCodeAtGenerator char_code_at_generator(receiver, 16879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block index, 16889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block scratch, 16899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block result, 16909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &miss, // When not a string. 16919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &miss, // When not a number. 1692b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch index_out_of_range_label, 16939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block STRING_INDEX_IS_NUMBER); 16949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block char_code_at_generator.GenerateFast(masm()); 16959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret((argc + 1) * kPointerSize); 1696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 16979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block StubRuntimeCallHelper call_helper; 16989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block char_code_at_generator.GenerateSlow(masm(), call_helper); 1699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1700b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch if (index_out_of_range.is_linked()) { 1701b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ bind(&index_out_of_range); 1702b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ LoadRoot(rax, Heap::kNanValueRootIndex); 1703b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ ret((argc + 1) * kPointerSize); 1704b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } 1705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 1707b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch // Restore function name in rcx. 1708b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ Move(rcx, Handle<String>(name)); 1709b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ bind(&name_miss); 171044f0eee88ff00398ff7f715fab053374d808c90dSteve Block MaybeObject* maybe_result = GenerateMissBranch(); 171144f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (maybe_result->IsFailure()) return maybe_result; 1712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 17149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(function); 1715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 17189fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileStringCharAtCall( 17199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Object* object, 17209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 17219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSGlobalPropertyCell* cell, 17229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSFunction* function, 17239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 1724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 17259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rcx : function name 17269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 17279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[(argc - n) * 8] : arg[n] (zero-based) 17289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- ... 17299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[(argc + 1) * 8] : receiver 173059151504615d929945dc59db37bf1166937748c6Steve Block // ----------------------------------- 173159151504615d929945dc59db37bf1166937748c6Steve Block 17329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // If object is not a string, bail out to regular call. 173344f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!object->IsString() || cell != NULL) return heap()->undefined_value(); 17349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 17359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const int argc = arguments().immediate(); 173659151504615d929945dc59db37bf1166937748c6Steve Block 1737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 1738b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch Label name_miss; 17399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label index_out_of_range; 1740b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch Label* index_out_of_range_label = &index_out_of_range; 1741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1742b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { 1743b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch index_out_of_range_label = &miss; 1744b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } 1745b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch 1746b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch GenerateNameCheck(name, &name_miss); 17479dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen 17489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the maps starting from the prototype haven't changed. 17499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateDirectLoadGlobalFunctionPrototype(masm(), 17509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Context::STRING_FUNCTION_INDEX, 17519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rax, 17529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &miss); 17539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(object != holder); 17549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 17559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rbx, rdx, rdi, name, &miss); 1756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 17579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register receiver = rax; 17589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register index = rdi; 17599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch1 = rbx; 17609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register scratch2 = rdx; 17619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register result = rax; 17629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); 17639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (argc > 0) { 17649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(index, Operand(rsp, (argc - 0) * kPointerSize)); 17659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { 17669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ LoadRoot(index, Heap::kUndefinedValueRootIndex); 1767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 17699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block StringCharAtGenerator char_at_generator(receiver, 17709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block index, 17719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block scratch1, 17729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block scratch2, 17739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block result, 17749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &miss, // When not a string. 17759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &miss, // When not a number. 1776b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch index_out_of_range_label, 17779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block STRING_INDEX_IS_NUMBER); 17789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block char_at_generator.GenerateFast(masm()); 17799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret((argc + 1) * kPointerSize); 17809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 17819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block StubRuntimeCallHelper call_helper; 17829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block char_at_generator.GenerateSlow(masm(), call_helper); 1783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1784b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch if (index_out_of_range.is_linked()) { 1785b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ bind(&index_out_of_range); 1786b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ LoadRoot(rax, Heap::kEmptyStringRootIndex); 1787b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ ret((argc + 1) * kPointerSize); 1788b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } 1789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 1791b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch // Restore function name in rcx. 1792b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ Move(rcx, Handle<String>(name)); 1793b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ bind(&name_miss); 179444f0eee88ff00398ff7f715fab053374d808c90dSteve Block MaybeObject* maybe_result = GenerateMissBranch(); 179544f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (maybe_result->IsFailure()) return maybe_result; 1796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 17989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(function); 1799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 18029fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileStringFromCharCodeCall( 18039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Object* object, 18049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 18059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSGlobalPropertyCell* cell, 18069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSFunction* function, 18079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 1808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 18099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rcx : function name 18109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 18119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[(argc - n) * 8] : arg[n] (zero-based) 18129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- ... 18139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[(argc + 1) * 8] : receiver 1814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 1815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 18169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const int argc = arguments().immediate(); 1817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 18189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // If the object is not a JSObject or we got an unexpected number of 18199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // arguments, bail out to the regular call. 182044f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!object->IsJSObject() || argc != 1) return heap()->undefined_value(); 1821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 18239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateNameCheck(name, &miss); 1824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 18259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (cell == NULL) { 18269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdx, Operand(rsp, 2 * kPointerSize)); 1827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 18289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(rdx, &miss); 1829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 18309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(JSObject::cast(object), rdx, holder, rbx, rax, rdi, name, 18319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &miss); 18329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { 18339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(cell->value() == function); 18349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); 18359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadFunctionFromCell(cell, function, &miss); 18369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 1837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 18389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Load the char code argument. 18399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Register code = rbx; 18409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(code, Operand(rsp, 1 * kPointerSize)); 18416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 18429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check the code is a smi. 18439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label slow; 18449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfNotSmi(code, &slow); 18456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 18469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Convert the smi code to uint16. 18479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ SmiAndConstant(code, code, Smi::FromInt(0xffff)); 18486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 18499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block StringCharFromCodeGenerator char_from_code_generator(code, rax); 18509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block char_from_code_generator.GenerateFast(masm()); 18519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret(2 * kPointerSize); 18526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 18539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block StubRuntimeCallHelper call_helper; 18549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block char_from_code_generator.GenerateSlow(masm(), call_helper); 18559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 18569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Tail call the full function. We do not have to patch the receiver 18579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // because the function makes no use of it. 18589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&slow); 18599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ InvokeFunction(function, arguments(), JUMP_FUNCTION); 18606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 18616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block __ bind(&miss); 18629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rcx: function name. 186344f0eee88ff00398ff7f715fab053374d808c90dSteve Block MaybeObject* maybe_result = GenerateMissBranch(); 186444f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (maybe_result->IsFailure()) return maybe_result; 18656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 18666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Return the generated code. 18679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); 18686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block} 18696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 18706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block 18719fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object, 18729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 18739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSGlobalPropertyCell* cell, 18749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSFunction* function, 18759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 18769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // TODO(872): implement this. 187744f0eee88ff00398ff7f715fab053374d808c90dSteve Block return heap()->undefined_value(); 1878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1880a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 18819fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object, 18829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 18839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSGlobalPropertyCell* cell, 18849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSFunction* function, 18859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 1886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 18879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rcx : function name 18889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 18899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[(argc - n) * 8] : arg[n] (zero-based) 18909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- ... 18919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[(argc + 1) * 8] : receiver 1892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 18939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 18949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const int argc = arguments().immediate(); 18959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 18969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // If the object is not a JSObject or we got an unexpected number of 18979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // arguments, bail out to the regular call. 189844f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!object->IsJSObject() || argc != 1) return heap()->undefined_value(); 18999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 1900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 19019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateNameCheck(name, &miss); 1902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 19039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (cell == NULL) { 19049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdx, Operand(rsp, 2 * kPointerSize)); 1905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 19069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(rdx, &miss); 1907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 19089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(JSObject::cast(object), rdx, holder, rbx, rax, rdi, name, 19099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &miss); 19109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { 19119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(cell->value() == function); 19129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); 19139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadFunctionFromCell(cell, function, &miss); 19149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 1915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 19169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Load the (only) argument into rax. 19179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rax, Operand(rsp, 1 * kPointerSize)); 1918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 19199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check if the argument is a smi. 19209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label not_smi; 19219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block STATIC_ASSERT(kSmiTag == 0); 19229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfNotSmi(rax, ¬_smi); 19239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ SmiToInteger32(rax, rax); 1924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 19259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0 19269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // otherwise. 19279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movl(rbx, rax); 19289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ sarl(rbx, Immediate(kBitsPerInt - 1)); 1929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 19309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Do bitwise not or do nothing depending on ebx. 19319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ xorl(rax, rbx); 1932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 19339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Add 1 or do nothing depending on ebx. 19349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ subl(rax, rbx); 19359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 19369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // If the result is still negative, go to the slow case. 19379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // This only happens for the most negative smi. 19389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label slow; 19399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(negative, &slow); 19409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 19419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Smi case done. 19429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Integer32ToSmi(rax, rax); 19439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret(2 * kPointerSize); 19449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 19459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check if the argument is a heap number and load its value. 19469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(¬_smi); 194744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CheckMap(rax, factory()->heap_number_map(), &slow, true); 19489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset)); 1949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 19509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check the sign of the argument. If the argument is positive, 19519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // just return it. 19529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label negative_sign; 19539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const int sign_mask_shift = 19549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block (HeapNumber::kExponentOffset - HeapNumber::kValueOffset) * kBitsPerByte; 19559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdi, static_cast<int64_t>(HeapNumber::kSignMask) << sign_mask_shift, 19569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block RelocInfo::NONE); 19579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ testq(rbx, rdi); 19589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_zero, &negative_sign); 19599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret(2 * kPointerSize); 1960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 19619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // If the argument is negative, clear the sign, and return a new 19629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // number. We still have the sign mask in rdi. 19639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&negative_sign); 19649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ xor_(rbx, rdi); 19659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ AllocateHeapNumber(rax, rdx, &slow); 19669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rbx); 19679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret(2 * kPointerSize); 1968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 19699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Tail call the full function. We do not have to patch the receiver 19709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // because the function makes no use of it. 19719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&slow); 19729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ InvokeFunction(function, arguments(), JUMP_FUNCTION); 1973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 19759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rcx: function name. 197644f0eee88ff00398ff7f715fab053374d808c90dSteve Block MaybeObject* maybe_result = GenerateMissBranch(); 197744f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (maybe_result->IsFailure()) return maybe_result; 1978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 19809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); 1981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 198444f0eee88ff00398ff7f715fab053374d808c90dSteve BlockMaybeObject* CallStubCompiler::CompileFastApiCall( 198544f0eee88ff00398ff7f715fab053374d808c90dSteve Block const CallOptimization& optimization, 198644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Object* object, 198744f0eee88ff00398ff7f715fab053374d808c90dSteve Block JSObject* holder, 198844f0eee88ff00398ff7f715fab053374d808c90dSteve Block JSGlobalPropertyCell* cell, 198944f0eee88ff00398ff7f715fab053374d808c90dSteve Block JSFunction* function, 199044f0eee88ff00398ff7f715fab053374d808c90dSteve Block String* name) { 199144f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT(optimization.is_simple_api_call()); 199244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Bail out if object is a global object as we don't want to 199344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // repatch it to global receiver. 199444f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (object->IsGlobalObject()) return heap()->undefined_value(); 199544f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (cell != NULL) return heap()->undefined_value(); 199644f0eee88ff00398ff7f715fab053374d808c90dSteve Block int depth = optimization.GetPrototypeDepthOfExpectedType( 199744f0eee88ff00398ff7f715fab053374d808c90dSteve Block JSObject::cast(object), holder); 199844f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (depth == kInvalidProtoDepth) return heap()->undefined_value(); 199944f0eee88ff00398ff7f715fab053374d808c90dSteve Block 200044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Label miss, miss_before_stack_reserved; 200144f0eee88ff00398ff7f715fab053374d808c90dSteve Block 200244f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateNameCheck(name, &miss_before_stack_reserved); 200344f0eee88ff00398ff7f715fab053374d808c90dSteve Block 200444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Get the receiver from the stack. 200544f0eee88ff00398ff7f715fab053374d808c90dSteve Block const int argc = arguments().immediate(); 200644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 200744f0eee88ff00398ff7f715fab053374d808c90dSteve Block 200844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Check that the receiver isn't a smi. 200944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ JumpIfSmi(rdx, &miss_before_stack_reserved); 201044f0eee88ff00398ff7f715fab053374d808c90dSteve Block 201144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 201244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->call_const(), 1); 201344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->call_const_fast_api(), 1); 201444f0eee88ff00398ff7f715fab053374d808c90dSteve Block 201544f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Allocate space for v8::Arguments implicit values. Must be initialized 201644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // before calling any runtime function. 201744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); 201844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 201944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Check that the maps haven't changed and find a Holder as a side effect. 202044f0eee88ff00398ff7f715fab053374d808c90dSteve Block CheckPrototypes(JSObject::cast(object), rdx, holder, 202144f0eee88ff00398ff7f715fab053374d808c90dSteve Block rbx, rax, rdi, name, depth, &miss); 202244f0eee88ff00398ff7f715fab053374d808c90dSteve Block 202344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Move the return address on top of the stack. 202444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(rax, Operand(rsp, 3 * kPointerSize)); 202544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(Operand(rsp, 0 * kPointerSize), rax); 202644f0eee88ff00398ff7f715fab053374d808c90dSteve Block 202744f0eee88ff00398ff7f715fab053374d808c90dSteve Block MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc); 202844f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (result->IsFailure()) return result; 202944f0eee88ff00398ff7f715fab053374d808c90dSteve Block 203044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&miss); 203144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); 203244f0eee88ff00398ff7f715fab053374d808c90dSteve Block 203344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&miss_before_stack_reserved); 203444f0eee88ff00398ff7f715fab053374d808c90dSteve Block MaybeObject* maybe_result = GenerateMissBranch(); 203544f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (maybe_result->IsFailure()) return maybe_result; 203644f0eee88ff00398ff7f715fab053374d808c90dSteve Block 203744f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Return the generated code. 203844f0eee88ff00398ff7f715fab053374d808c90dSteve Block return GetCode(function); 203944f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 204044f0eee88ff00398ff7f715fab053374d808c90dSteve Block 204144f0eee88ff00398ff7f715fab053374d808c90dSteve Block 20429fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileCallConstant(Object* object, 20439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 20449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSFunction* function, 20459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name, 20469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckType check) { 2047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 20489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rcx : function name 20499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[0] : return address 20509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[8] : argument argc 20519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[16] : argument argc - 1 20529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ... 20539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[argc * 8] : argument 1 20549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[(argc + 1) * 8] : argument 0 = receiver 2055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 205744f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (HasCustomCallGenerator(function)) { 20589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block MaybeObject* maybe_result = CompileCustomCall( 205944f0eee88ff00398ff7f715fab053374d808c90dSteve Block object, holder, NULL, function, name); 20609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Object* result; 20619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (!maybe_result->ToObject(&result)) return maybe_result; 20629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // undefined means bail out to regular compiler. 20639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (!result->IsUndefined()) return result; 20640d5e116f6aee03185f237311a943491bb079a768Kristian Monsen } 2065e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke 206644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Label miss; 2067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 206844f0eee88ff00398ff7f715fab053374d808c90dSteve Block GenerateNameCheck(name, &miss); 2069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 20709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the receiver from the stack. 20719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const int argc = arguments().immediate(); 20729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 2073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 20749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the receiver isn't a smi. 20759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (check != NUMBER_CHECK) { 207644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ JumpIfSmi(rdx, &miss); 20779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 2078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 20799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Make sure that it's okay not to patch the on stack receiver 20809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // unless we're doing a receiver map check. 20819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); 2082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 208344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 208444f0eee88ff00398ff7f715fab053374d808c90dSteve Block SharedFunctionInfo* function_info = function->shared(); 20859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block switch (check) { 20869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block case RECEIVER_MAP_CHECK: 208744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->call_const(), 1); 2088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 20899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the maps haven't changed. 20909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(JSObject::cast(object), rdx, holder, 209144f0eee88ff00398ff7f715fab053374d808c90dSteve Block rbx, rax, rdi, name, &miss); 2092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 20939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Patch the receiver on the stack with the global proxy if 20949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // necessary. 20959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (object->IsGlobalObject()) { 20969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); 20979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); 20989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 20999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block break; 2100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 21019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block case STRING_CHECK: 2102e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (!function->IsBuiltin() && !function_info->strict_mode()) { 2103e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Calling non-strict non-builtins with a value as the receiver 2104e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // requires boxing. 21059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ jmp(&miss); 21069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { 21079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the object is a two-byte string or a symbol. 21089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax); 21099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(above_equal, &miss); 21109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the maps starting from the prototype haven't changed. 21119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateDirectLoadGlobalFunctionPrototype( 21129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block masm(), Context::STRING_FUNCTION_INDEX, rax, &miss); 21139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 21149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rbx, rdx, rdi, name, &miss); 21159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 21169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block break; 2117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 21189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block case NUMBER_CHECK: { 2119e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (!function->IsBuiltin() && !function_info->strict_mode()) { 2120e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Calling non-strict non-builtins with a value as the receiver 2121e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // requires boxing. 21229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ jmp(&miss); 21239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { 21249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label fast; 21259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the object is a smi or a heap number. 21269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(rdx, &fast); 21279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax); 21289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &miss); 21299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&fast); 21309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the maps starting from the prototype haven't changed. 21319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateDirectLoadGlobalFunctionPrototype( 21329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss); 21339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 21349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rbx, rdx, rdi, name, &miss); 21359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 21369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block break; 21379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 2138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 21399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block case BOOLEAN_CHECK: { 2140e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (!function->IsBuiltin() && !function_info->strict_mode()) { 2141e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Calling non-strict non-builtins with a value as the receiver 2142e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // requires boxing. 21439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ jmp(&miss); 21449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else { 21459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label fast; 21469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the object is a boolean. 21479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CompareRoot(rdx, Heap::kTrueValueRootIndex); 21489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(equal, &fast); 21499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CompareRoot(rdx, Heap::kFalseValueRootIndex); 21509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &miss); 21519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&fast); 21529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the maps starting from the prototype haven't changed. 21539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateDirectLoadGlobalFunctionPrototype( 21549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss); 21559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 21569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rbx, rdx, rdi, name, &miss); 21579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 21589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block break; 21599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 2160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 21619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block default: 21629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block UNREACHABLE(); 21639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 2164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 216544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ InvokeFunction(function, arguments(), JUMP_FUNCTION); 2166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 21679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Handle call cache miss. 2168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 216944f0eee88ff00398ff7f715fab053374d808c90dSteve Block MaybeObject* maybe_result = GenerateMissBranch(); 217044f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (maybe_result->IsFailure()) return maybe_result; 2171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 21739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(function); 2174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 21779fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, 21789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 21799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 2180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 21819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rcx : function name 21829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[0] : return address 21839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[8] : argument argc 21849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[16] : argument argc - 1 21859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ... 21869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[argc * 8] : argument 1 21879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[(argc + 1) * 8] : argument 0 = receiver 2188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 2190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 21919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateNameCheck(name, &miss); 2192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 21939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the number of arguments. 21949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const int argc = arguments().immediate(); 2195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LookupResult lookup; 2197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LookupPostInterceptor(holder, name, &lookup); 21989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 21999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the receiver from the stack. 22009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 22019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 22029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CallInterceptorCompiler compiler(this, arguments(), rcx); 22031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block MaybeObject* result = compiler.Compile(masm(), 22041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block object, 22051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block holder, 22061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block name, 22071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block &lookup, 22081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block rdx, 22091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block rbx, 22101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block rdi, 22111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block rax, 22121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block &miss); 22131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (result->IsFailure()) return result; 22149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 22159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Restore receiver. 22169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 22179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 22189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the function really is a function. 22199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(rax, &miss); 22209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); 22219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &miss); 22229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 22239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Patch the receiver on the stack with the global proxy if 22249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // necessary. 22259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (object->IsGlobalObject()) { 22269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); 22279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); 22289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 22299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 22309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Invoke the function. 22319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdi, rax); 22329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION); 22339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 22349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Handle load cache miss. 2235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 223644f0eee88ff00398ff7f715fab053374d808c90dSteve Block MaybeObject* maybe_result = GenerateMissBranch(); 223744f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (maybe_result->IsFailure()) return maybe_result; 2238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 2240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(INTERCEPTOR, name); 2241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 22449fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object, 22459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GlobalObject* holder, 22469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSGlobalPropertyCell* cell, 22479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSFunction* function, 22489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 2249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 22509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rcx : function name 22519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[0] : return address 22529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[8] : argument argc 22539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[16] : argument argc - 1 22549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ... 22559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[argc * 8] : argument 1 22569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // rsp[(argc + 1) * 8] : argument 0 = receiver 2257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 22589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 225944f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (HasCustomCallGenerator(function)) { 22609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block MaybeObject* maybe_result = CompileCustomCall( 226144f0eee88ff00398ff7f715fab053374d808c90dSteve Block object, holder, cell, function, name); 22629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Object* result; 22639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (!maybe_result->ToObject(&result)) return maybe_result; 22649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // undefined means bail out to regular compiler. 22659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (!result->IsUndefined()) return result; 22669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 22679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 2268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 2269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 22709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateNameCheck(name, &miss); 2271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 22729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the number of arguments. 22739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block const int argc = arguments().immediate(); 2274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 22759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateGlobalReceiverCheck(object, holder, name, &miss); 22769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 22779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadFunctionFromCell(cell, function, &miss); 22789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 22799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Patch the receiver on the stack with the global proxy. 22809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (object->IsGlobalObject()) { 22819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); 22829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); 22839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 22849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 2285b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch // Setup the context (function already in rdi). 22869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); 22879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 22889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Jump to the cached code (tail call). 228944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 229044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->call_global_inline(), 1); 22919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ASSERT(function->is_compiled()); 22929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ParameterCount expected(function->shared()->formal_parameter_count()); 2293b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch if (V8::UseCrankshaft()) { 2294b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch // TODO(kasperl): For now, we always call indirectly through the 2295b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch // code field in the function to allow recompilation to take effect 2296b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch // without changing any of the call sites. 2297b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); 2298b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION); 2299b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } else { 2300b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch Handle<Code> code(function->code()); 2301b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch __ InvokeCode(code, expected, arguments(), 2302b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch RelocInfo::CODE_TARGET, JUMP_FUNCTION); 2303b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } 23049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Handle call cache miss. 2305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 230644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->call_global_inline_miss(), 1); 230744f0eee88ff00398ff7f715fab053374d808c90dSteve Block MaybeObject* maybe_result = GenerateMissBranch(); 230844f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (maybe_result->IsFailure()) return maybe_result; 2309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 23119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(NORMAL, name); 2312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 23159fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object, 23169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block int index, 23179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Map* transition, 23189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 2319b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ----------- S t a t e ------------- 23209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : value 23219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rcx : name 2322b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // -- rdx : receiver 23239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 2324b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ----------------------------------- 2325b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label miss; 2326b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 23279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Generate store field code. Preserves receiver and name on jump to miss. 23289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateStoreField(masm(), 23299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block object, 23309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block index, 23319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block transition, 23329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rdx, rcx, rbx, 23339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &miss); 2334b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 23359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Handle store cache miss. 2336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&miss); 233744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Handle<Code> ic = isolate()->builtins()->StoreIC_Miss(); 23389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Jump(ic, RelocInfo::CODE_TARGET); 2339b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2340b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Return the generated code. 23419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); 2342b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 2343b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2344b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 23455913587db4c6bab03d97bfe44b06289fd6d7270dJohn ReckMaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object, 23465913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck AccessorInfo* callback, 23475913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck String* name) { 2348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 2349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rax : value 2350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rcx : name 23514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // -- rdx : receiver 2352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 2353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 2355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the object isn't a smi. 23574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ JumpIfSmi(rdx, &miss); 2358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the map of the object hasn't changed. 23604515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), 2361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Map>(object->map())); 2362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 2363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Perform global security token check if needed. 2365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (object->IsJSGlobalProxy()) { 23664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ CheckAccessGlobalProxy(rdx, rbx, &miss); 2367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Stub never generated for non-global objects that require access 2370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // checks. 2371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); 2372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rbx); // remove the return address 23749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(rdx); // receiver 23759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Push(Handle<AccessorInfo>(callback)); // callback info 23769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(rcx); // name 23779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(rax); // value 23789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ push(rbx); // restore return address 23799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 23809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Do tail-call to the runtime system. 23819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block ExternalReference store_callback_property = 238244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); 23839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ TailCallExternalReference(store_callback_property, 4, 1); 2384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle store cache miss. 2386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 238744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Handle<Code> ic = isolate()->builtins()->StoreIC_Miss(); 2388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Jump(ic, RelocInfo::CODE_TARGET); 2389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 23919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(CALLBACKS, name); 2392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 23955913587db4c6bab03d97bfe44b06289fd6d7270dJohn ReckMaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, 23965913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck String* name) { 2397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 2398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rax : value 2399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rcx : name 24004515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // -- rdx : receiver 2401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 2402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 2404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the object isn't a smi. 24064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ JumpIfSmi(rdx, &miss); 2407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the map of the object hasn't changed. 24094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), 2410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Map>(receiver->map())); 2411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 2412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Perform global security token check if needed. 2414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (receiver->IsJSGlobalProxy()) { 24154515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ CheckAccessGlobalProxy(rdx, rbx, &miss); 2416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 2417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Stub never generated for non-global objects that require access 2419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // checks. 2420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); 2421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rbx); // remove the return address 24234515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ push(rdx); // receiver 2424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rcx); // name 2425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rax); // value 2426e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Push(Smi::FromInt(strict_mode_)); 2427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rbx); // restore return address 2428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Do tail-call to the runtime system. 2430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExternalReference store_ic_property = 243144f0eee88ff00398ff7f715fab053374d808c90dSteve Block ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate()); 2432e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ TailCallExternalReference(store_ic_property, 4, 1); 2433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle store cache miss. 2435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 243644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Handle<Code> ic = isolate()->builtins()->StoreIC_Miss(); 2437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Jump(ic, RelocInfo::CODE_TARGET); 2438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 2440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(INTERCEPTOR, name); 2441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 24445913587db4c6bab03d97bfe44b06289fd6d7270dJohn ReckMaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, 24455913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck JSGlobalPropertyCell* cell, 24465913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck String* name) { 2447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 2448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rax : value 2449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rcx : name 24504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke // -- rdx : receiver 2451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 2452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 2454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the map of the global has not changed. 24564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), 2457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Map>(object->map())); 2458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 2459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 24601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check that the value in the cell is not the hole. If it is, this 24611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // cell could have been deleted and reintroducing the global needs 24621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // to update the property details in the property dictionary of the 24631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // global object. We bail out to the runtime system to do that. 24641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Move(rbx, Handle<JSGlobalPropertyCell>(cell)); 24651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ CompareRoot(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), 24661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Heap::kTheHoleValueRootIndex); 24671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ j(equal, &miss); 24681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 2469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Store the value in the cell. 24701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), rax); 2471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the value (register rax). 247344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 247444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->named_store_global_inline(), 1); 2475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 2476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle store cache miss. 2478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 247944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->named_store_global_inline_miss(), 1); 248044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Handle<Code> ic = isolate()->builtins()->StoreIC_Miss(); 2481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Jump(ic, RelocInfo::CODE_TARGET); 2482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 2484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(NORMAL, name); 2485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 24885913587db4c6bab03d97bfe44b06289fd6d7270dJohn ReckMaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, 24895913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck int index, 24905913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck Map* transition, 24915913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck String* name) { 2492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 2493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rax : value 2494f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // -- rcx : key 2495f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // -- rdx : receiver 2496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 2497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 2498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label miss; 2499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 250044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 250144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->keyed_store_field(), 1); 2502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that the name has not changed. 2504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Cmp(rcx, Handle<String>(name)); 2505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &miss); 2506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2507402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu // Generate store field code. Preserves receiver and name on jump to miss. 2508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block GenerateStoreField(masm(), 2509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block object, 2510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index, 2511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block transition, 2512402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu rdx, rcx, rbx, 2513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &miss); 2514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Handle store cache miss. 2516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&miss); 251744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ DecrementCounter(counters->keyed_store_field(), 1); 251844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); 2519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Jump(ic, RelocInfo::CODE_TARGET); 2520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 2522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); 2523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2526b0fe1620dcb4135ac3ab2d66ff93072373911299Ben MurdochMaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized( 2527b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch JSObject* receiver) { 2528b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ----------- S t a t e ------------- 2529b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // -- rax : value 2530b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // -- rcx : key 2531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // -- rdx : receiver 2532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // -- rsp[0] : return address 2533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // ----------------------------------- 2534b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Label miss; 2535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2536b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check that the receiver isn't a smi. 2537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ JumpIfSmi(rdx, &miss); 2538b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2539b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check that the map matches. 2540b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), 2541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Handle<Map>(receiver->map())); 2542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_equal, &miss); 2543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check that the key is a smi. 2545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ JumpIfNotSmi(rcx, &miss); 2546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Get the elements array and make sure it is a fast element array, not 'cow'. 2548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); 2549b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset), 255044f0eee88ff00398ff7f715fab053374d808c90dSteve Block factory()->fixed_array_map()); 2551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(not_equal, &miss); 2552b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Check that the key is within bounds. 2554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (receiver->IsJSArray()) { 2555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); 2556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(above_equal, &miss); 2557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 2558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset)); 2559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ j(above_equal, &miss); 2560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 2561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Do the store and update the write barrier. Make sure to preserve 2563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // the value in register eax. 2564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(rdx, rax); 2565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ SmiToInteger32(rcx, rcx); 2566b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize), 2567b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch rax); 2568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ RecordWrite(rdi, 0, rdx, rcx); 2569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Done. 2571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ ret(0); 2572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 2573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Handle store cache miss. 2574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch __ bind(&miss); 257544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); 2576e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ jmp(ic, RelocInfo::CODE_TARGET); 2577e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2578e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch // Return the generated code. 2579e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch return GetCode(NORMAL, NULL); 2580e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch} 2581e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 2582e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 25839fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, 25849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* object, 25859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* last) { 25869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------- S t a t e ------------- 25879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : receiver 25889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rcx : name 25899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 25909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------------------------------- 25919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 25927f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 25939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Chech that receiver is not a smi. 25949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(rax, &miss); 25957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 25969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check the maps of the full prototype chain. Also check that 25979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // global property cells up to (but not including) the last object 25989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // in the prototype chain are empty. 25999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(object, rax, last, rbx, rdx, rdi, name, &miss); 26009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // If the last object in the prototype chain is a global object, 26029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // check that the global property cell is empty. 26039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (last->IsGlobalObject()) { 26049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block MaybeObject* cell = GenerateCheckPropertyCell(masm(), 26059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GlobalObject::cast(last), 26069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block name, 26079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rdx, 26089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &miss); 26099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (cell->IsFailure()) { 26109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block miss.Unuse(); 26119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return cell; 26127f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } 26137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch } 26147f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 26159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return undefined if maps of the full prototype chain are still the 26169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // same and no global property with this name contains a value. 26179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); 26189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret(0); 26199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&miss); 26219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadMiss(masm(), Code::LOAD_IC); 26229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the generated code. 262444f0eee88ff00398ff7f715fab053374d808c90dSteve Block return GetCode(NONEXISTENT, heap()->empty_string()); 26259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 26269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26289fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object, 26299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 26309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block int index, 26319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 26329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------- S t a t e ------------- 26339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : receiver 26349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rcx : name 26359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 26369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------------------------------- 26379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 26389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadField(object, holder, rax, rbx, rdx, rdi, index, name, &miss); 26409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&miss); 26419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadMiss(masm(), Code::LOAD_IC); 26429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the generated code. 26449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(FIELD, name); 26459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 26469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26489fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* LoadStubCompiler::CompileLoadCallback(String* name, 26499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* object, 26509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 26519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block AccessorInfo* callback) { 26529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------- S t a t e ------------- 26539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : receiver 26549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rcx : name 26559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 26569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------------------------------- 26579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 26589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block MaybeObject* result = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, 26601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block rdi, callback, name, &miss); 26611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (result->IsFailure()) { 26629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block miss.Unuse(); 26631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block return result; 26649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 26659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&miss); 26679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadMiss(masm(), Code::LOAD_IC); 26689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26699fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the generated code. 26709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(CALLBACKS, name); 26719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 26729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26749fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object, 26759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 26769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Object* value, 26779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 26789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------- S t a t e ------------- 26799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : receiver 26809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rcx : name 26819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 26829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------------------------------- 26839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 26849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadConstant(object, holder, rax, rbx, rdx, rdi, value, name, &miss); 26869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&miss); 26879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadMiss(masm(), Code::LOAD_IC); 26889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the generated code. 26909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(CONSTANT_FUNCTION, name); 26919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 26929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 26949fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, 26959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 26969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 26979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------- S t a t e ------------- 26989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : receiver 26999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rcx : name 27009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 27019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------------------------------- 27029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 27039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 27049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block LookupResult lookup; 27059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block LookupPostInterceptor(holder, name, &lookup); 27069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 27079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // TODO(368): Compile in the whole chain: all the interceptors in 27089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // prototypes and ultimate answer. 27099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadInterceptor(receiver, 27109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block holder, 27119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &lookup, 27129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rax, 27139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rcx, 27149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rdx, 27159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rbx, 27169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rdi, 27179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block name, 27189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &miss); 27199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 27209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&miss); 27219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadMiss(masm(), Code::LOAD_IC); 27229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 27239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the generated code. 27249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(INTERCEPTOR, name); 27259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 27269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 27279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 27289fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object, 27299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GlobalObject* holder, 27309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSGlobalPropertyCell* cell, 27319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name, 27329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block bool is_dont_delete) { 27339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------- S t a t e ------------- 27349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : receiver 27359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rcx : name 27369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 27379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------------------------------- 27389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 27399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 27409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // If the object is the holder then we know that it's a global 27419fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // object which can only happen for contextual loads. In this case, 27429fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // the receiver cannot be a smi. 27439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (object != holder) { 27449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(rax, &miss); 27459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 27469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 27479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the maps haven't changed. 27489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block CheckPrototypes(object, rax, holder, rbx, rdx, rdi, name, &miss); 27499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 27509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the value from the cell. 27519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Move(rbx, Handle<JSGlobalPropertyCell>(cell)); 27529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset)); 27539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 27549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check for deleted property if property can actually be deleted. 27559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block if (!is_dont_delete) { 27569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); 27579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(equal, &miss); 27589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } else if (FLAG_debug_code) { 27599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); 27609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Check(not_equal, "DontDelete cells can't contain the hole"); 27619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 27629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 276344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 276444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->named_load_global_stub(), 1); 27659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rax, rbx); 27669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ ret(0); 27679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 27689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&miss); 276944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->named_load_global_stub_miss(), 1); 27709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadMiss(masm(), Code::LOAD_IC); 27717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 27729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the generated code. 27739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(NORMAL, name); 27749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 27757f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 27767f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 27779fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name, 27789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* receiver, 27799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 27809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block int index) { 27819fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------- S t a t e ------------- 27829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : key 27839fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rdx : receiver 27849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 27859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------------------------------- 27869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 27877f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 278844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 278944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->keyed_load_field(), 1); 27907f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 27919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the name has not changed. 27929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(rax, Handle<String>(name)); 27939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &miss); 27947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 27959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss); 27967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 27979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&miss); 279844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ DecrementCounter(counters->keyed_load_field(), 1); 27999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 28007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 28019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the generated code. 28029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(FIELD, name); 28039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 28047f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 28057f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 28069fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( 28079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name, 28089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* receiver, 28099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 28109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block AccessorInfo* callback) { 28119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------- S t a t e ------------- 28129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : key 28139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rdx : receiver 28149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 28159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------------------------------- 28169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 28177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch 281844f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 281944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->keyed_load_callback(), 1); 2820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 28219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the name has not changed. 28229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(rax, Handle<String>(name)); 28239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &miss); 2824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 28251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block MaybeObject* result = GenerateLoadCallback(receiver, holder, rdx, rax, rbx, 28261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block rcx, rdi, callback, name, &miss); 28271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (result->IsFailure()) { 28289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block miss.Unuse(); 28291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block return result; 28309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block } 2831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 28329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&miss); 2833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 283444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ DecrementCounter(counters->keyed_load_callback(), 1); 28359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 2836bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch 28379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the generated code. 28389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(CALLBACKS, name); 28399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 28408a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang 2841bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch 28429fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name, 28439fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* receiver, 28449fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 28459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Object* value) { 28469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------- S t a t e ------------- 28479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : key 28489fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rdx : receiver 28499fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 28509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------------------------------- 28519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 2852bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch 285344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 285444f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->keyed_load_constant_function(), 1); 2855bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch 28569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the name has not changed. 28579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(rax, Handle<String>(name)); 28589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &miss); 28598a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang 28609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadConstant(receiver, holder, rdx, rbx, rcx, rdi, 28619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block value, name, &miss); 28629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&miss); 286344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ DecrementCounter(counters->keyed_load_constant_function(), 1); 28649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 28658a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang 28669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the generated code. 28679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(CONSTANT_FUNCTION, name); 28689fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 28698a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang 28708a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang 28719fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, 28729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block JSObject* holder, 28739fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block String* name) { 28749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------- S t a t e ------------- 28759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : key 28769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rdx : receiver 28779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 28789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------------------------------- 28799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 28808a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang 288144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 288244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->keyed_load_interceptor(), 1); 28838a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang 28849fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the name has not changed. 28859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(rax, Handle<String>(name)); 28869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &miss); 28879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 28889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block LookupResult lookup; 28899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block LookupPostInterceptor(holder, name, &lookup); 28909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadInterceptor(receiver, 28919fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block holder, 28929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &lookup, 28939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rdx, 28949fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rax, 28959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rcx, 28969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rbx, 28979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block rdi, 28989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block name, 28999fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block &miss); 29009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&miss); 290144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ DecrementCounter(counters->keyed_load_interceptor(), 1); 29029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 29039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 29049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the generated code. 29059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(INTERCEPTOR, name); 2906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2908a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 29099fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { 29109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------- S t a t e ------------- 29119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : key 29129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rdx : receiver 29139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 29149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------------------------------- 29159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 29163bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 291744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 291844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->keyed_load_array_length(), 1); 29193bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 29209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the name has not changed. 29219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(rax, Handle<String>(name)); 29229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &miss); 29233bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 29249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadArrayLength(masm(), rdx, rcx, &miss); 29259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&miss); 292644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ DecrementCounter(counters->keyed_load_array_length(), 1); 29279fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 29283bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 29299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the generated code. 29309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(CALLBACKS, name); 29319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 29323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 29333bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 29349fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { 29359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------- S t a t e ------------- 29369fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : key 29379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rdx : receiver 29389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 29399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------------------------------- 29409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 29413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 294244f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 294344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->keyed_load_string_length(), 1); 29443bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 29459fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the name has not changed. 29469fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(rax, Handle<String>(name)); 29479fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &miss); 29483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 29491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss, true); 29509fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&miss); 295144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ DecrementCounter(counters->keyed_load_string_length(), 1); 29529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 29533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 29549fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the generated code. 29559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(CALLBACKS, name); 29569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 29573bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 29583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 29599fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { 29609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------- S t a t e ------------- 29619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : key 29629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rdx : receiver 29639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rsp[0] : return address 29649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------------------------------- 29659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 29663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch 296744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 296844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->keyed_load_function_prototype(), 1); 2969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 29709fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the name has not changed. 29719fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(rax, Handle<String>(name)); 29729fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &miss); 2973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 29749fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss); 29759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&miss); 297644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ DecrementCounter(counters->keyed_load_function_prototype(), 1); 29779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 29789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 29799fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the generated code. 29809fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(CALLBACKS, name); 2981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 2982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 29849fac840a46e8b7e26894f4792ba26dde14c56b04Steve BlockMaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) { 29859fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------- S t a t e ------------- 29869fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rax : key 29879fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // -- rdx : receiver 298844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // -- rsp[0] : return address 29899fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // ----------------------------------- 29909fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Label miss; 2991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 29929fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the receiver isn't a smi. 29939fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfSmi(rdx, &miss); 2994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 29959fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the map matches. 29969fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), 29979fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block Handle<Map>(receiver->map())); 29989fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(not_equal, &miss); 2999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 30009fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the key is a smi. 30019fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ JumpIfNotSmi(rax, &miss); 3002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 30039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Get the elements array. 30049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); 30059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ AssertFastElements(rcx); 3006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 30079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Check that the key is within bounds. 30089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset)); 30099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(above_equal, &miss); 3010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 30119fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Load the result and make sure it's not the hole. 30129fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block SmiIndex index = masm()->SmiToIndex(rbx, rax, kPointerSizeLog2); 30139fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rbx, FieldOperand(rcx, 30149fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block index.reg, 30159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block index.scale, 30169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block FixedArray::kHeaderSize)); 30179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); 30189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ j(equal, &miss); 30199fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ movq(rax, rbx); 3020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 30219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 30229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block __ bind(&miss); 30239fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 30249fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 30259fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block // Return the generated code. 30269fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return GetCode(NORMAL, NULL); 3027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Specialized stub for constructing objects from functions which only have only 3031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// simple assignments of the form this.x = ...; in their body. 30328a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) WangMaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { 3033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------- S t a t e ------------- 3034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rax : argc 3035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rdi : constructor 3036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[0] : return address 3037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // -- rsp[4] : last argument 3038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ----------------------------------- 3039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Label generic_stub_call; 3040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Use r8 for holding undefined which is used in several places below. 304244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Move(r8, factory()->undefined_value()); 3043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_DEBUGGER_SUPPORT 3045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check to see whether there are any break points in the function code. If 3046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // there are jump to the generic constructor stub which calls the actual 3047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // code for the function thereby hitting the break points. 3048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); 3049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kDebugInfoOffset)); 3050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rbx, r8); 3051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &generic_stub_call); 3052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 3053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the initial map and verify that it is in fact a map. 3055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); 3056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Will both indicate a NULL and a Smi. 3057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(kSmiTag == 0); 3058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ JumpIfSmi(rbx, &generic_stub_call); 3059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpObjectType(rbx, MAP_TYPE, rcx); 3060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ j(not_equal, &generic_stub_call); 3061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG 3063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Cannot construct functions this way. 3064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdi: constructor 3065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbx: initial map 3066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ CmpInstanceType(rbx, JS_FUNCTION_TYPE); 3067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Assert(not_equal, "Function constructed by construct stub."); 3068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 3069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Now allocate the JSObject in new space. 3071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdi: constructor 3072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbx: initial map 3073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset)); 3074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ shl(rcx, Immediate(kPointerSizeLog2)); 3075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ AllocateInNewSpace(rcx, 3076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block rdx, 3077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block rcx, 3078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block no_reg, 3079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block &generic_stub_call, 3080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block NO_ALLOCATION_FLAGS); 3081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Allocated the JSObject, now initialize the fields and add the heap tag. 3083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbx: initial map 3084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdx: JSObject (untagged) 3085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rdx, JSObject::kMapOffset), rbx); 308644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ Move(rbx, factory()->empty_fixed_array()); 3087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rdx, JSObject::kPropertiesOffset), rbx); 3088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(rdx, JSObject::kElementsOffset), rbx); 3089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: argc 3091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdx: JSObject (untagged) 3092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Load the address of the first in-object property into r9. 3093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ lea(r9, Operand(rdx, JSObject::kHeaderSize)); 3094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Calculate the location of the first argument. The stack contains only the 3095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // return address on top of the argc arguments. 3096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ lea(rcx, Operand(rsp, rax, times_pointer_size, 0)); 3097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: argc 3099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rcx: first argument 3100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdx: JSObject (untagged) 3101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // r8: undefined 3102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // r9: first in-object property of the JSObject 3103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fill the initialized properties with a constant value or a passed argument 3104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // depending on the this.x = ...; assignment in the function. 31058a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang SharedFunctionInfo* shared = function->shared(); 3106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < shared->this_property_assignments_count(); i++) { 3107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (shared->IsThisPropertyAssignmentArgument(i)) { 3108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check if the argument assigned to the property is actually passed. 3109e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // If argument is not passed the property is set to undefined, 3110e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // otherwise find it on the stack. 3111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int arg_number = shared->GetThisPropertyAssignmentArgument(i); 3112e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ movq(rbx, r8); 3113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ cmpq(rax, Immediate(arg_number)); 3114e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke __ cmovq(above, rbx, Operand(rcx, arg_number * -kPointerSize)); 3115e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // Store value in the property. 3116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(r9, i * kPointerSize), rbx); 3117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 3118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Set the property to the constant value. 3119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i)); 3120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Move(Operand(r9, i * kPointerSize), constant); 3121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Fill the unused in-object property fields with undefined. 31258a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang ASSERT(function->has_initial_map()); 3126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = shared->this_property_assignments_count(); 31278a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang i < function->initial_map()->inobject_properties(); 3128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i++) { 3129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(Operand(r9, i * kPointerSize), r8); 3130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 3131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: argc 3133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rdx: JSObject (untagged) 3134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Move argc to rbx and the JSObject to return to rax and tag it. 3135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rbx, rax); 3136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ movq(rax, rdx); 3137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ or_(rax, Immediate(kHeapObjectTag)); 3138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rax: JSObject 3140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // rbx: argc 3141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Remove caller arguments and receiver from the stack and return. 3142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ pop(rcx); 3143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ lea(rsp, Operand(rsp, rbx, times_pointer_size, 1 * kPointerSize)); 3144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ push(rcx); 314544f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 314644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->constructed_objects(), 1); 314744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->constructed_objects_stub(), 1); 3148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ ret(0); 3149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Jump to the generic stub in case the specialized code cannot handle the 3151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // construction. 3152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ bind(&generic_stub_call); 315344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Code* code = 315444f0eee88ff00398ff7f715fab053374d808c90dSteve Block isolate()->builtins()->builtin(Builtins::kJSConstructStubGeneric); 3155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Handle<Code> generic_construct_stub(code); 3156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); 3157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return the generated code. 3159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return GetCode(); 3160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 3161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 31631e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockMaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( 316444f0eee88ff00398ff7f715fab053374d808c90dSteve Block JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) { 31651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // ----------- S t a t e ------------- 31661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // -- rax : key 31671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // -- rdx : receiver 31681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // -- rsp[0] : return address 31691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // ----------------------------------- 31701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label slow; 31711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 31721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check that the object isn't a smi. 31731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfSmi(rdx, &slow); 31741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 31751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check that the key is a smi. 31761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfNotSmi(rax, &slow); 31771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 317844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Check that the map matches. 317944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, false); 31801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); 31811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 31821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check that the index is in range. 31831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiToInteger32(rcx, rax); 31841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset)); 31851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Unsigned comparison catches both negative and too-large values. 31861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ j(above_equal, &slow); 31871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 31881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rax: index (as a smi) 31891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rdx: receiver (JSObject) 31901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rcx: untagged index 31911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rbx: elements array 31921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); 31931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rbx: base pointer of external storage 31941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block switch (array_type) { 31951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case kExternalByteArray: 31961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movsxbq(rcx, Operand(rbx, rcx, times_1, 0)); 31971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 319844f0eee88ff00398ff7f715fab053374d808c90dSteve Block case kExternalPixelArray: 31991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case kExternalUnsignedByteArray: 32001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movzxbq(rcx, Operand(rbx, rcx, times_1, 0)); 32011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 32021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case kExternalShortArray: 32031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movsxwq(rcx, Operand(rbx, rcx, times_2, 0)); 32041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 32051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case kExternalUnsignedShortArray: 32061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movzxwq(rcx, Operand(rbx, rcx, times_2, 0)); 32071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 32081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case kExternalIntArray: 32091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movsxlq(rcx, Operand(rbx, rcx, times_4, 0)); 32101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 32111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case kExternalUnsignedIntArray: 32121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movl(rcx, Operand(rbx, rcx, times_4, 0)); 32131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 32141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case kExternalFloatArray: 32151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ cvtss2sd(xmm0, Operand(rbx, rcx, times_4, 0)); 32161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 32171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block default: 32181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block UNREACHABLE(); 32191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 32201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 32211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rax: index 32231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rdx: receiver 32241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // For integer array types: 32251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rcx: value 32261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // For floating-point array type: 32271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // xmm0: value as double. 32281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block ASSERT(kSmiValueSize == 32); 32301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (array_type == kExternalUnsignedIntArray) { 32311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // For the UnsignedInt array type, we need to see whether 32321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // the value can be represented in a Smi. If not, we need to convert 32331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // it to a HeapNumber. 32341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block NearLabel box_int; 32351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfUIntNotValidSmiValue(rcx, &box_int); 32371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Integer32ToSmi(rax, rcx); 32391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 32401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&box_int); 32421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Allocate a HeapNumber for the int and perform int-to-double 32441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // conversion. 32451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // The value is zero-extended since we loaded the value from memory 32461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // with movl. 32471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ cvtqsi2sd(xmm0, rcx); 32481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ AllocateHeapNumber(rcx, rbx, &slow); 32501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Set the value. 32511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0); 32521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rax, rcx); 32531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 32541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else if (array_type == kExternalFloatArray) { 32551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // For the floating-point array type, we need to always allocate a 32561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // HeapNumber. 32571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ AllocateHeapNumber(rcx, rbx, &slow); 32581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Set the value. 32591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0); 32601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rax, rcx); 32611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 32621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } else { 32631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ Integer32ToSmi(rax, rcx); 32641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 32651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 32661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Slow case: Jump to runtime. 32681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&slow); 326944f0eee88ff00398ff7f715fab053374d808c90dSteve Block Counters* counters = isolate()->counters(); 327044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ IncrementCounter(counters->keyed_load_external_array_slow(), 1); 32711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // ----------- S t a t e ------------- 32731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // -- rax : key 32741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // -- rdx : receiver 32751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // -- rsp[0] : return address 32761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // ----------------------------------- 32771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ pop(rbx); 32791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rdx); // receiver 32801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rax); // name 32811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rbx); // return address 32821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Perform tail call to the entry. 32841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); 32851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Return the generated code. 32871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block return GetCode(flags); 32881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 32891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 32911e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockMaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( 329244f0eee88ff00398ff7f715fab053374d808c90dSteve Block JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) { 32931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // ----------- S t a t e ------------- 32941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // -- rax : value 32951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // -- rcx : key 32961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // -- rdx : receiver 32971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // -- rsp[0] : return address 32981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // ----------------------------------- 32991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block Label slow; 33001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 33011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check that the object isn't a smi. 33021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ JumpIfSmi(rdx, &slow); 33031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 330444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Check that the map matches. 330544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, false); 33061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); 330744f0eee88ff00398ff7f715fab053374d808c90dSteve Block 330844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Check that the key is a smi. 330944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ JumpIfNotSmi(rcx, &slow); 33101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 33111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Check that the index is in range. 33121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiToInteger32(rdi, rcx); // Untag the index. 33131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ cmpl(rdi, FieldOperand(rbx, ExternalArray::kLengthOffset)); 33141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Unsigned comparison catches both negative and too-large values. 33151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ j(above_equal, &slow); 33161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 33171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Handle both smis and HeapNumbers in the fast path. Go to the 33181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // runtime for all other kinds of values. 33191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rax: value 33201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rcx: key (a smi) 33211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rdx: receiver (a JSObject) 33221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rbx: elements array 33231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rdi: untagged key 33241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block NearLabel check_heap_number; 332544f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (array_type == kExternalPixelArray) { 332644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Float to pixel conversion is only implemented in the runtime for now. 332744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ JumpIfNotSmi(rax, &slow); 332844f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 332944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ JumpIfNotSmi(rax, &check_heap_number); 333044f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 33311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // No more branches to slow case on this path. Key and receiver not needed. 33321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ SmiToInteger32(rdx, rax); 33331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); 33341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rbx: base pointer of external storage 33351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block switch (array_type) { 333644f0eee88ff00398ff7f715fab053374d808c90dSteve Block case kExternalPixelArray: 333744f0eee88ff00398ff7f715fab053374d808c90dSteve Block { // Clamp the value to [0..255]. 333844f0eee88ff00398ff7f715fab053374d808c90dSteve Block NearLabel done; 333944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ testl(rdx, Immediate(0xFFFFFF00)); 334044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ j(zero, &done); 334144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ setcc(negative, rdx); // 1 if negative, 0 if positive. 334244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ decb(rdx); // 0 if negative, 255 if positive. 334344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&done); 334444f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 334544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movb(Operand(rbx, rdi, times_1, 0), rdx); 334644f0eee88ff00398ff7f715fab053374d808c90dSteve Block break; 33471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case kExternalByteArray: 33481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case kExternalUnsignedByteArray: 33491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movb(Operand(rbx, rdi, times_1, 0), rdx); 33501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 33511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case kExternalShortArray: 33521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case kExternalUnsignedShortArray: 33531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movw(Operand(rbx, rdi, times_2, 0), rdx); 33541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 33551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case kExternalIntArray: 33561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case kExternalUnsignedIntArray: 33571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movl(Operand(rbx, rdi, times_4, 0), rdx); 33581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 33591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block case kExternalFloatArray: 33601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Need to perform int-to-float conversion. 33611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ cvtlsi2ss(xmm0, rdx); 33621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ movss(Operand(rbx, rdi, times_4, 0), xmm0); 33631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 33641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block default: 33651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block UNREACHABLE(); 33661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block break; 33671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 33681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ ret(0); 33691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 337044f0eee88ff00398ff7f715fab053374d808c90dSteve Block // TODO(danno): handle heap number -> pixel array conversion 337144f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (array_type != kExternalPixelArray) { 337244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ bind(&check_heap_number); 337344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rax: value 337444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rcx: key (a smi) 337544f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rdx: receiver (a JSObject) 337644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rbx: elements array 337744f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rdi: untagged key 337844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister); 337944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ j(not_equal, &slow); 338044f0eee88ff00398ff7f715fab053374d808c90dSteve Block // No more branches to slow case on this path. 338144f0eee88ff00398ff7f715fab053374d808c90dSteve Block 338244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // The WebGL specification leaves the behavior of storing NaN and 338344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // +/-Infinity into integer arrays basically undefined. For more 338444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // reproducible behavior, convert these to zero. 338544f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); 338644f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); 33871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rdi: untagged index 33881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // rbx: base pointer of external storage 338944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // top of FPU stack: value 339044f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (array_type == kExternalFloatArray) { 339144f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cvtsd2ss(xmm0, xmm0); 339244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movss(Operand(rbx, rdi, times_4, 0), xmm0); 339344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ ret(0); 339444f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 339544f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Perform float-to-int conversion with truncation (round-to-zero) 339644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // behavior. 339744f0eee88ff00398ff7f715fab053374d808c90dSteve Block 339844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Convert to int32 and store the low byte/word. 339944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // If the value is NaN or +/-infinity, the result is 0x80000000, 340044f0eee88ff00398ff7f715fab053374d808c90dSteve Block // which is automatically zero when taken mod 2^n, n < 32. 340144f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rdx: value (converted to an untagged integer) 340244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rdi: untagged index 340344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // rbx: base pointer of external storage 340444f0eee88ff00398ff7f715fab053374d808c90dSteve Block switch (array_type) { 340544f0eee88ff00398ff7f715fab053374d808c90dSteve Block case kExternalByteArray: 340644f0eee88ff00398ff7f715fab053374d808c90dSteve Block case kExternalUnsignedByteArray: 340744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cvttsd2si(rdx, xmm0); 340844f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movb(Operand(rbx, rdi, times_1, 0), rdx); 340944f0eee88ff00398ff7f715fab053374d808c90dSteve Block break; 341044f0eee88ff00398ff7f715fab053374d808c90dSteve Block case kExternalShortArray: 341144f0eee88ff00398ff7f715fab053374d808c90dSteve Block case kExternalUnsignedShortArray: 341244f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cvttsd2si(rdx, xmm0); 341344f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movw(Operand(rbx, rdi, times_2, 0), rdx); 341444f0eee88ff00398ff7f715fab053374d808c90dSteve Block break; 341544f0eee88ff00398ff7f715fab053374d808c90dSteve Block case kExternalIntArray: 341644f0eee88ff00398ff7f715fab053374d808c90dSteve Block case kExternalUnsignedIntArray: { 341744f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Convert to int64, so that NaN and infinities become 341844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // 0x8000000000000000, which is zero mod 2^32. 341944f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ cvttsd2siq(rdx, xmm0); 342044f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ movl(Operand(rbx, rdi, times_4, 0), rdx); 342144f0eee88ff00398ff7f715fab053374d808c90dSteve Block break; 342244f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 342344f0eee88ff00398ff7f715fab053374d808c90dSteve Block default: 342444f0eee88ff00398ff7f715fab053374d808c90dSteve Block UNREACHABLE(); 342544f0eee88ff00398ff7f715fab053374d808c90dSteve Block break; 34261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 342744f0eee88ff00398ff7f715fab053374d808c90dSteve Block __ ret(0); 34281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 34291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block } 34301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 34311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Slow case: call runtime. 34321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ bind(&slow); 34331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 34341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // ----------- S t a t e ------------- 34351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // -- rax : value 34361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // -- rcx : key 34371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // -- rdx : receiver 34381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // -- rsp[0] : return address 34391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // ----------------------------------- 34401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 34411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ pop(rbx); 34421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rdx); // receiver 34431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rcx); // key 34441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rax); // value 3445e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Push(Smi::FromInt(NONE)); // PropertyAttributes 3446e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ Push(Smi::FromInt( 3447e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch Code::ExtractExtraICStateFromFlags(flags) & kStrictMode)); 34481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block __ push(rbx); // return address 34491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 34501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block // Do tail-call to runtime routine. 3451e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch __ TailCallRuntime(Runtime::kSetProperty, 5, 1); 34521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 34531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block return GetCode(flags); 34541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 34551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 3456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __ 3457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 3458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} } // namespace v8::internal 3459f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke 3460f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#endif // V8_TARGET_ARCH_X64 3461