blob: 950ee28e1c4f1609e03378535b1fdcf26cbbc202 [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5ec48922009-05-05 07:25:34 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
ager@chromium.org5aa501c2009-06-23 07:57:28 +000028#include "v8.h"
29
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_X64
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000031
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000032#include "arguments.h"
ager@chromium.org5aa501c2009-06-23 07:57:28 +000033#include "ic-inl.h"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000034#include "codegen.h"
ager@chromium.org5aa501c2009-06-23 07:57:28 +000035#include "stub-cache.h"
36
37namespace v8 {
38namespace internal {
39
kasperl@chromium.orge959c182009-07-27 08:59:04 +000040#define __ ACCESS_MASM(masm)
41
42
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000043static void ProbeTable(Isolate* isolate,
44 MacroAssembler* masm,
kasperl@chromium.orge959c182009-07-27 08:59:04 +000045 Code::Flags flags,
46 StubCache::Table table,
ulan@chromium.org812308e2012-02-29 15:58:45 +000047 Register receiver,
kasperl@chromium.orge959c182009-07-27 08:59:04 +000048 Register name,
ulan@chromium.org812308e2012-02-29 15:58:45 +000049 // The offset is scaled by 4, based on
50 // kHeapObjectTagSize, which is two bits
kasperl@chromium.orge959c182009-07-27 08:59:04 +000051 Register offset) {
ulan@chromium.org812308e2012-02-29 15:58:45 +000052 // We need to scale up the pointer by 2 because the offset is scaled by less
53 // than the pointer size.
54 ASSERT(kPointerSizeLog2 == kHeapObjectTagSize + 1);
55 ScaleFactor scale_factor = times_2;
56
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000057 ASSERT_EQ(3 * kPointerSize, sizeof(StubCache::Entry));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000058 // The offset register holds the entry offset times four (due to masking
59 // and shifting optimizations).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000060 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
ulan@chromium.org812308e2012-02-29 15:58:45 +000061 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
kasperl@chromium.orge959c182009-07-27 08:59:04 +000062 Label miss;
63
ulan@chromium.org812308e2012-02-29 15:58:45 +000064 // Multiply by 3 because there are 3 fields per entry (name, code, map).
65 __ lea(offset, Operand(offset, offset, times_2, 0));
66
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 __ LoadAddress(kScratchRegister, key_offset);
ulan@chromium.org812308e2012-02-29 15:58:45 +000068
kasperl@chromium.orge959c182009-07-27 08:59:04 +000069 // Check that the key in the entry matches the name.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000070 // Multiply entry offset by 16 to get the entry address. Since the
71 // offset register already holds the entry offset times four, multiply
72 // by a further four.
ulan@chromium.org812308e2012-02-29 15:58:45 +000073 __ cmpl(name, Operand(kScratchRegister, offset, scale_factor, 0));
kasperl@chromium.orge959c182009-07-27 08:59:04 +000074 __ j(not_equal, &miss);
ulan@chromium.org812308e2012-02-29 15:58:45 +000075
76 // Get the map entry from the cache.
77 // Use key_offset + kPointerSize * 2, rather than loading map_offset.
kasperl@chromium.orge959c182009-07-27 08:59:04 +000078 __ movq(kScratchRegister,
ulan@chromium.org812308e2012-02-29 15:58:45 +000079 Operand(kScratchRegister, offset, scale_factor, kPointerSize * 2));
80 __ cmpq(kScratchRegister, FieldOperand(receiver, HeapObject::kMapOffset));
81 __ j(not_equal, &miss);
82
83 // Get the code entry from the cache.
84 __ LoadAddress(kScratchRegister, value_offset);
85 __ movq(kScratchRegister,
86 Operand(kScratchRegister, offset, scale_factor, 0));
87
kasperl@chromium.orge959c182009-07-27 08:59:04 +000088 // Check that the flags match what we're looking for.
89 __ movl(offset, FieldOperand(kScratchRegister, Code::kFlagsOffset));
90 __ and_(offset, Immediate(~Code::kFlagsNotUsedInLookup));
91 __ cmpl(offset, Immediate(flags));
92 __ j(not_equal, &miss);
93
ulan@chromium.org812308e2012-02-29 15:58:45 +000094#ifdef DEBUG
95 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
96 __ jmp(&miss);
97 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
98 __ jmp(&miss);
99 }
100#endif
101
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000102 // Jump to the first instruction in the code stub.
103 __ addq(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag));
104 __ jmp(kScratchRegister);
105
106 __ bind(&miss);
107}
108
109
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000110void StubCompiler::GenerateDictionaryNegativeLookup(MacroAssembler* masm,
111 Label* miss_label,
112 Register receiver,
113 Handle<Name> name,
114 Register scratch0,
115 Register scratch1) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000116 ASSERT(name->IsUniqueName());
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000117 ASSERT(!receiver.is(scratch0));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000118 Counters* counters = masm->isolate()->counters();
119 __ IncrementCounter(counters->negative_lookups(), 1);
120 __ IncrementCounter(counters->negative_lookups_miss(), 1);
121
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000122 __ movq(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000123
124 const int kInterceptorOrAccessCheckNeededMask =
125 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
126
127 // Bail out if the receiver has a named interceptor or requires access checks.
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000128 __ testb(FieldOperand(scratch0, Map::kBitFieldOffset),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000129 Immediate(kInterceptorOrAccessCheckNeededMask));
130 __ j(not_zero, miss_label);
131
132 // Check that receiver is a JSObject.
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000133 __ CmpInstanceType(scratch0, FIRST_SPEC_OBJECT_TYPE);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000134 __ j(below, miss_label);
135
136 // Load properties array.
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000137 Register properties = scratch0;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000138 __ movq(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
139
140 // Check that the properties array is a dictionary.
141 __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset),
142 Heap::kHashTableMapRootIndex);
143 __ j(not_equal, miss_label);
144
145 Label done;
ulan@chromium.org750145a2013-03-07 15:14:13 +0000146 NameDictionaryLookupStub::GenerateNegativeLookup(masm,
147 miss_label,
148 &done,
149 properties,
150 name,
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000151 scratch1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000152 __ bind(&done);
153 __ DecrementCounter(counters->negative_lookups_miss(), 1);
154}
155
156
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000157void StubCache::GenerateProbe(MacroAssembler* masm,
158 Code::Flags flags,
159 Register receiver,
160 Register name,
161 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000162 Register extra,
ulan@chromium.org812308e2012-02-29 15:58:45 +0000163 Register extra2,
164 Register extra3) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000165 Isolate* isolate = masm->isolate();
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000166 Label miss;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000167 USE(extra); // The register extra is not used on the X64 platform.
168 USE(extra2); // The register extra2 is not used on the X64 platform.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000169 USE(extra3); // The register extra2 is not used on the X64 platform.
170 // Make sure that code is valid. The multiplying code relies on the
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000171 // entry size being 3 * kPointerSize.
172 ASSERT(sizeof(Entry) == 3 * kPointerSize);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000173
174 // Make sure the flags do not name a specific type.
175 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
176
177 // Make sure that there are no register conflicts.
178 ASSERT(!scratch.is(receiver));
179 ASSERT(!scratch.is(name));
180
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000181 // Check scratch register is valid, extra and extra2 are unused.
182 ASSERT(!scratch.is(no_reg));
183 ASSERT(extra2.is(no_reg));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000184 ASSERT(extra3.is(no_reg));
185
186 Counters* counters = masm->isolate()->counters();
187 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000188
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000189 // Check that the receiver isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000190 __ JumpIfSmi(receiver, &miss);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000191
192 // Get the map of the receiver and compute the hash.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000193 __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000194 // Use only the low 32 bits of the map pointer.
195 __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
196 __ xor_(scratch, Immediate(flags));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000197 // We mask out the last two bits because they are not part of the hash and
198 // they are always 01 for maps. Also in the two 'and' instructions below.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000199 __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
200
201 // Probe the primary table.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000202 ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000203
204 // Primary miss: Compute hash for secondary probe.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000205 __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000206 __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
207 __ xor_(scratch, Immediate(flags));
208 __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
209 __ subl(scratch, name);
210 __ addl(scratch, Immediate(flags));
211 __ and_(scratch, Immediate((kSecondaryTableSize - 1) << kHeapObjectTagSize));
212
213 // Probe the secondary table.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000214 ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000215
216 // Cache miss: Fall-through and let caller handle the miss by
217 // entering the runtime system.
218 __ bind(&miss);
ulan@chromium.org812308e2012-02-29 15:58:45 +0000219 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000220}
221
222
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000223void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
224 int index,
225 Register prototype) {
226 // Load the global or builtins object from the current context.
227 __ movq(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000228 Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
229 // Load the native context from the global or builtins object.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000230 __ movq(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000231 FieldOperand(prototype, GlobalObject::kNativeContextOffset));
232 // Load the function from the native context.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000233 __ movq(prototype, Operand(prototype, Context::SlotOffset(index)));
234 // Load the initial map. The global functions all have initial maps.
235 __ movq(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000236 FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000237 // Load the prototype from the initial map.
238 __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
239}
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000240
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000241
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000242void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000243 MacroAssembler* masm,
244 int index,
245 Register prototype,
246 Label* miss) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000247 Isolate* isolate = masm->isolate();
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000248 // Check we're still in the same context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000249 __ Move(prototype, isolate->global_object());
250 __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)),
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000251 prototype);
252 __ j(not_equal, miss);
253 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000254 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000255 JSFunction::cast(isolate->native_context()->get(index)));
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000256 // Load its initial map. The global functions all have initial maps.
257 __ Move(prototype, Handle<Map>(function->initial_map()));
258 // Load the prototype from the initial map.
259 __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000260}
261
262
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000263void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
264 Register receiver,
265 Register scratch,
266 Label* miss_label) {
267 // Check that the receiver isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000268 __ JumpIfSmi(receiver, miss_label);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000269
270 // Check that the object is a JS array.
271 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
272 __ j(not_equal, miss_label);
273
274 // Load length directly from the JS array.
275 __ movq(rax, FieldOperand(receiver, JSArray::kLengthOffset));
276 __ ret(0);
277}
278
279
280// Generate code to check if an object is a string. If the object is
281// a string, the map's instance type is left in the scratch register.
282static void GenerateStringCheck(MacroAssembler* masm,
283 Register receiver,
284 Register scratch,
285 Label* smi,
286 Label* non_string_object) {
287 // Check that the object isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000288 __ JumpIfSmi(receiver, smi);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000289
290 // Check that the object is a string.
291 __ movq(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
292 __ movzxbq(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000293 STATIC_ASSERT(kNotStringTag != 0);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000294 __ testl(scratch, Immediate(kNotStringTag));
295 __ j(not_zero, non_string_object);
296}
297
298
299void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
300 Register receiver,
ager@chromium.org5c838252010-02-19 08:53:10 +0000301 Register scratch1,
302 Register scratch2,
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000303 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000304 Label check_wrapper;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000305
306 // Check if the object is a string leaving the instance type in the
307 // scratch register.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000308 GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000309
310 // Load length directly from the string.
ager@chromium.orgac091b72010-05-05 07:34:42 +0000311 __ movq(rax, FieldOperand(receiver, String::kLengthOffset));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000312 __ ret(0);
313
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000314 // Check if the object is a JSValue wrapper.
315 __ bind(&check_wrapper);
316 __ cmpl(scratch1, Immediate(JS_VALUE_TYPE));
317 __ j(not_equal, miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000318
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000319 // Check if the wrapped value is a string and load the length
320 // directly if it is.
321 __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
322 GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
323 __ movq(rax, FieldOperand(scratch2, String::kLengthOffset));
324 __ ret(0);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000325}
326
327
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000328void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
329 Register receiver,
330 Register result,
331 Register scratch,
332 Label* miss_label) {
333 __ TryGetFunctionPrototype(receiver, result, miss_label);
334 if (!result.is(rax)) __ movq(rax, result);
335 __ ret(0);
336}
337
338
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000339void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
340 Register dst,
341 Register src,
342 bool inobject,
343 int index,
344 Representation representation) {
345 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000346 int offset = index * kPointerSize;
347 if (!inobject) {
348 // Calculate the offset into the properties array.
349 offset = offset + FixedArray::kHeaderSize;
350 __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
351 src = dst;
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000352 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000353 __ movq(dst, FieldOperand(src, offset));
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000354}
355
356
357static void PushInterceptorArguments(MacroAssembler* masm,
358 Register receiver,
359 Register holder,
360 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000361 Handle<JSObject> holder_obj) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000362 STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0);
363 STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1);
364 STATIC_ASSERT(StubCache::kInterceptorArgsThisIndex == 2);
365 STATIC_ASSERT(StubCache::kInterceptorArgsHolderIndex == 3);
366 STATIC_ASSERT(StubCache::kInterceptorArgsLength == 4);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000367 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000368 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
369 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
370 __ Move(kScratchRegister, interceptor);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000371 __ push(kScratchRegister);
372 __ push(receiver);
373 __ push(holder);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000374}
375
376
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000377static void CompileCallLoadPropertyWithInterceptor(
378 MacroAssembler* masm,
379 Register receiver,
380 Register holder,
381 Register name,
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000382 Handle<JSObject> holder_obj,
383 IC::UtilityId id) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000384 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000385 __ CallExternalReference(
386 ExternalReference(IC_Utility(id), masm->isolate()),
387 StubCache::kInterceptorArgsLength);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000388}
389
390
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000391// Number of pointers to be reserved on stack for fast API call.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000392static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000393
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000394
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000395// Reserves space for the extra arguments to API function in the
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000396// caller's frame.
397//
398// These arguments are set by CheckPrototypes and GenerateFastApiCall.
399static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
400 // ----------- S t a t e -------------
401 // -- rsp[0] : return address
402 // -- rsp[8] : last argument in the internal frame of the caller
403 // -----------------------------------
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000404 __ movq(scratch, StackOperandForReturnAddress(0));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000405 __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000406 __ movq(StackOperandForReturnAddress(0), scratch);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000407 __ Move(scratch, Smi::FromInt(0));
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000408 StackArgumentsAccessor args(rsp, kFastApiCallArguments,
409 ARGUMENTS_DONT_CONTAIN_RECEIVER);
410 for (int i = 0; i < kFastApiCallArguments; i++) {
411 __ movq(args.GetArgumentOperand(i), scratch);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000412 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000413}
414
415
416// Undoes the effects of ReserveSpaceForFastApiCall.
417static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
418 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +0000419 // -- rsp[0] : return address.
420 // -- rsp[8] : last fast api call extra argument.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000421 // -- ...
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +0000422 // -- rsp[kFastApiCallArguments * 8] : first fast api call extra
423 // argument.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000424 // -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal
425 // frame.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000426 // -----------------------------------
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000427 __ movq(scratch, StackOperandForReturnAddress(0));
428 __ movq(StackOperandForReturnAddress(kFastApiCallArguments * kPointerSize),
429 scratch);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000430 __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000431}
432
433
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000434static void GenerateFastApiCallBody(MacroAssembler* masm,
435 const CallOptimization& optimization,
436 int argc,
437 bool restore_context);
438
439
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000440// Generates call to API function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000441static void GenerateFastApiCall(MacroAssembler* masm,
442 const CallOptimization& optimization,
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000443 int argc) {
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000444 typedef FunctionCallbackArguments FCA;
445 StackArgumentsAccessor args(rsp, argc + kFastApiCallArguments);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000446
447 // Save calling context.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000448 int offset = argc + kFastApiCallArguments;
449 __ movq(args.GetArgumentOperand(offset - FCA::kContextSaveIndex), rsi);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000450
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000451 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000452 Handle<JSFunction> function = optimization.constant_function();
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000453 __ Move(rdi, function);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000454 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000455 // Construct the FunctionCallbackInfo on the stack.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000456 __ movq(args.GetArgumentOperand(offset - FCA::kCalleeIndex), rdi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000457 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000458 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000459 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
460 __ Move(rcx, api_call_info);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000461 __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000462 __ movq(args.GetArgumentOperand(offset - FCA::kDataIndex), rbx);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000463 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000464 __ Move(args.GetArgumentOperand(offset - FCA::kDataIndex), call_data);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000465 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000466 __ Move(kScratchRegister,
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000467 ExternalReference::isolate_address(masm->isolate()));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000468 __ movq(args.GetArgumentOperand(offset - FCA::kIsolateIndex),
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000469 kScratchRegister);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000470 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000471 __ movq(args.GetArgumentOperand(offset - FCA::kReturnValueDefaultValueIndex),
472 kScratchRegister);
473 __ movq(args.GetArgumentOperand(offset - FCA::kReturnValueOffset),
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000474 kScratchRegister);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000475
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000476 // Prepare arguments.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000477 STATIC_ASSERT(kFastApiCallArguments == 7);
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000478 __ lea(rax, Operand(rsp, 1 * kPointerSize));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000479
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000480 GenerateFastApiCallBody(masm, optimization, argc, false);
481}
482
483
484// Generate call to api function.
485// This function uses push() to generate smaller, faster code than
486// the version above. It is an optimization that should will be removed
487// when api call ICs are generated in hydrogen.
488static void GenerateFastApiCall(MacroAssembler* masm,
489 const CallOptimization& optimization,
490 Register receiver,
491 Register scratch1,
492 Register scratch2,
493 Register scratch3,
494 int argc,
495 Register* values) {
496 ASSERT(optimization.is_simple_api_call());
497
498 // Copy return value.
499 __ pop(scratch1);
500
501 // receiver
502 __ push(receiver);
503
504 // Write the arguments to stack frame.
505 for (int i = 0; i < argc; i++) {
506 Register arg = values[argc-1-i];
507 ASSERT(!receiver.is(arg));
508 ASSERT(!scratch1.is(arg));
509 ASSERT(!scratch2.is(arg));
510 ASSERT(!scratch3.is(arg));
511 __ push(arg);
512 }
513
514 typedef FunctionCallbackArguments FCA;
515
516 STATIC_ASSERT(FCA::kHolderIndex == 0);
517 STATIC_ASSERT(FCA::kIsolateIndex == 1);
518 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
519 STATIC_ASSERT(FCA::kReturnValueOffset == 3);
520 STATIC_ASSERT(FCA::kDataIndex == 4);
521 STATIC_ASSERT(FCA::kCalleeIndex == 5);
522 STATIC_ASSERT(FCA::kContextSaveIndex == 6);
523 STATIC_ASSERT(FCA::kArgsLength == 7);
524
525 // context save
526 __ push(rsi);
527
528 // Get the function and setup the context.
529 Handle<JSFunction> function = optimization.constant_function();
530 __ Move(scratch2, function);
531 __ push(scratch2);
532
533 Isolate* isolate = masm->isolate();
534 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
535 Handle<Object> call_data(api_call_info->data(), isolate);
536 // Push data from ExecutableAccessorInfo.
537 bool call_data_undefined = false;
538 if (isolate->heap()->InNewSpace(*call_data)) {
539 __ Move(scratch2, api_call_info);
540 __ movq(scratch3, FieldOperand(scratch2, CallHandlerInfo::kDataOffset));
541 } else if (call_data->IsUndefined()) {
542 call_data_undefined = true;
543 __ LoadRoot(scratch3, Heap::kUndefinedValueRootIndex);
544 } else {
545 __ Move(scratch3, call_data);
546 }
547 // call data
548 __ push(scratch3);
549 if (!call_data_undefined) {
550 __ LoadRoot(scratch3, Heap::kUndefinedValueRootIndex);
551 }
552 // return value
553 __ push(scratch3);
554 // return value default
555 __ push(scratch3);
556 // isolate
557 __ Move(scratch3,
558 ExternalReference::isolate_address(masm->isolate()));
559 __ push(scratch3);
560 // holder
561 __ push(receiver);
562
563 ASSERT(!scratch1.is(rax));
564 // store receiver address for GenerateFastApiCallBody
565 __ movq(rax, rsp);
566
567 // return address
568 __ push(scratch1);
569
570 GenerateFastApiCallBody(masm, optimization, argc, true);
571}
572
573
574static void GenerateFastApiCallBody(MacroAssembler* masm,
575 const CallOptimization& optimization,
576 int argc,
577 bool restore_context) {
578 // ----------- S t a t e -------------
579 // -- rsp[0] : return address
580 // -- rsp[8] - rsp[56] : FunctionCallbackInfo, incl.
581 // : object passing the type check
582 // (set by CheckPrototypes)
583 // -- rsp[64] : last argument
584 // -- ...
585 // -- rsp[(argc + 7) * 8] : first argument
586 // -- rsp[(argc + 8) * 8] : receiver
587 //
588 // rax : receiver address
589 // -----------------------------------
590 typedef FunctionCallbackArguments FCA;
591
592 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000593 // Function address is a foreign pointer outside V8's heap.
594 Address function_address = v8::ToCData<Address>(api_call_info->callback());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000595
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000596 // Allocate the v8::Arguments structure in the arguments' space since
597 // it's not controlled by GC.
598 const int kApiStackSpace = 4;
599
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000600 __ PrepareCallApiFunction(kApiStackSpace);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000601
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000602 __ movq(StackSpaceOperand(0), rax); // FunctionCallbackInfo::implicit_args_.
603 __ addq(rax, Immediate((argc + kFastApiCallArguments - 1) * kPointerSize));
604 __ movq(StackSpaceOperand(1), rax); // FunctionCallbackInfo::values_.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000605 __ Set(StackSpaceOperand(2), argc); // FunctionCallbackInfo::length_.
606 // FunctionCallbackInfo::is_construct_call_.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000607 __ Set(StackSpaceOperand(3), 0);
608
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000609#if defined(__MINGW64__) || defined(_WIN64)
610 Register arguments_arg = rcx;
611 Register callback_arg = rdx;
612#else
613 Register arguments_arg = rdi;
614 Register callback_arg = rsi;
615#endif
616
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000617 // v8::InvocationCallback's argument.
618 __ lea(arguments_arg, StackSpaceOperand(0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000619
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000620 Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000621
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000622 StackArgumentsAccessor args_from_rbp(rbp, kFastApiCallArguments,
623 ARGUMENTS_DONT_CONTAIN_RECEIVER);
624 Operand context_restore_operand = args_from_rbp.GetArgumentOperand(
625 kFastApiCallArguments - 1 - FCA::kContextSaveIndex);
626 Operand return_value_operand = args_from_rbp.GetArgumentOperand(
627 kFastApiCallArguments - 1 - FCA::kReturnValueOffset);
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000628 __ CallApiFunctionAndReturn(
629 function_address,
630 thunk_address,
631 callback_arg,
632 argc + kFastApiCallArguments + 1,
633 return_value_operand,
634 restore_context ? &context_restore_operand : NULL);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000635}
636
637
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000638class CallInterceptorCompiler BASE_EMBEDDED {
639 public:
machenbach@chromium.org8a58f642013-12-02 10:46:30 +0000640 CallInterceptorCompiler(CallStubCompiler* stub_compiler,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000641 const ParameterCount& arguments,
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +0000642 Register name)
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000643 : stub_compiler_(stub_compiler),
644 arguments_(arguments),
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +0000645 name_(name) {}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000646
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000647 void Compile(MacroAssembler* masm,
648 Handle<JSObject> object,
649 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000650 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000651 LookupResult* lookup,
652 Register receiver,
653 Register scratch1,
654 Register scratch2,
655 Register scratch3,
656 Label* miss) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000657 ASSERT(holder->HasNamedInterceptor());
658 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
659
660 // Check that the receiver isn't a smi.
661 __ JumpIfSmi(receiver, miss);
662
663 CallOptimization optimization(lookup);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000664 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000665 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
666 holder, lookup, name, optimization, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000667 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000668 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
669 name, holder, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000670 }
671 }
672
673 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000674 void CompileCacheable(MacroAssembler* masm,
675 Handle<JSObject> object,
676 Register receiver,
677 Register scratch1,
678 Register scratch2,
679 Register scratch3,
680 Handle<JSObject> interceptor_holder,
681 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000682 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000683 const CallOptimization& optimization,
684 Label* miss_label) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000685 ASSERT(optimization.is_constant_call());
ager@chromium.org5c838252010-02-19 08:53:10 +0000686 ASSERT(!lookup->holder()->IsGlobalObject());
687
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000688 int depth1 = kInvalidProtoDepth;
689 int depth2 = kInvalidProtoDepth;
690 bool can_do_fast_api_call = false;
691 if (optimization.is_simple_api_call() &&
692 !lookup->holder()->IsGlobalObject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000693 depth1 = optimization.GetPrototypeDepthOfExpectedType(
694 object, interceptor_holder);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000695 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000696 depth2 = optimization.GetPrototypeDepthOfExpectedType(
697 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000698 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000699 can_do_fast_api_call =
700 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000701 }
702
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000703 Counters* counters = masm->isolate()->counters();
704 __ IncrementCounter(counters->call_const_interceptor(), 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000705
706 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000707 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000708 ReserveSpaceForFastApiCall(masm, scratch1);
709 }
710
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000711 // Check that the maps from receiver to interceptor's holder
712 // haven't changed and thus we can invoke interceptor.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000713 Label miss_cleanup;
714 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
715 Register holder =
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000716 stub_compiler_->CheckPrototypes(
717 IC::CurrentTypeOf(object, masm->isolate()), receiver,
718 interceptor_holder, scratch1, scratch2, scratch3,
719 name, depth1, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000720
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000721 // Invoke an interceptor and if it provides a value,
722 // branch to |regular_invoke|.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000723 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000724 LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
725 &regular_invoke);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000726
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000727 // Interceptor returned nothing for this property. Try to use cached
728 // constant function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000729
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000730 // Check that the maps from interceptor's holder to constant function's
731 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000732 if (*interceptor_holder != lookup->holder()) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000733 stub_compiler_->CheckPrototypes(
jkummerow@chromium.org113035e2013-12-13 15:13:40 +0000734 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder,
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000735 handle(lookup->holder()), scratch1, scratch2, scratch3,
736 name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000737 } else {
738 // CheckPrototypes has a side effect of fetching a 'holder'
739 // for API (object which is instanceof for the signature). It's
740 // safe to omit it here, as if present, it should be fetched
741 // by the previous CheckPrototypes.
742 ASSERT(depth2 == kInvalidProtoDepth);
743 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000744
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000745 // Invoke function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000746 if (can_do_fast_api_call) {
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000747 GenerateFastApiCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000748 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000749 Handle<JSFunction> fun = optimization.constant_function();
jkummerow@chromium.org113035e2013-12-13 15:13:40 +0000750 stub_compiler_->GenerateJumpFunction(object, fun);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000751 }
752
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000753 // Deferred code for fast API call case---clean preallocated space.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000754 if (can_do_fast_api_call) {
755 __ bind(&miss_cleanup);
756 FreeSpaceForFastApiCall(masm, scratch1);
757 __ jmp(miss_label);
758 }
759
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000760 // Invoke a regular function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000761 __ bind(&regular_invoke);
762 if (can_do_fast_api_call) {
763 FreeSpaceForFastApiCall(masm, scratch1);
764 }
765 }
766
767 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000768 Handle<JSObject> object,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000769 Register receiver,
770 Register scratch1,
771 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000772 Register scratch3,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000773 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000774 Handle<JSObject> interceptor_holder,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000775 Label* miss_label) {
776 Register holder =
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000777 stub_compiler_->CheckPrototypes(
778 IC::CurrentTypeOf(object, masm->isolate()), receiver,
779 interceptor_holder, scratch1, scratch2, scratch3, name, miss_label);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000780
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000781 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000782 // Save the name_ register across the call.
783 __ push(name_);
784
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000785 CompileCallLoadPropertyWithInterceptor(
786 masm, receiver, holder, name_, interceptor_holder,
787 IC::kLoadPropertyWithInterceptorForCall);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000788
789 // Restore the name_ register.
790 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000791
792 // Leave the internal frame.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000793 }
794
795 void LoadWithInterceptor(MacroAssembler* masm,
796 Register receiver,
797 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000798 Handle<JSObject> holder_obj,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000799 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000800 {
801 FrameScope scope(masm, StackFrame::INTERNAL);
jkummerow@chromium.org113035e2013-12-13 15:13:40 +0000802 __ push(receiver);
803 __ push(holder);
804 __ push(name_);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000805
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000806 CompileCallLoadPropertyWithInterceptor(
807 masm, receiver, holder, name_, holder_obj,
808 IC::kLoadPropertyWithInterceptorOnly);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000809
jkummerow@chromium.org113035e2013-12-13 15:13:40 +0000810 __ pop(name_);
811 __ pop(holder);
812 __ pop(receiver);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000813 // Leave the internal frame.
814 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000815
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000816 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000817 __ j(not_equal, interceptor_succeeded);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000818 }
819
machenbach@chromium.org8a58f642013-12-02 10:46:30 +0000820 CallStubCompiler* stub_compiler_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000821 const ParameterCount& arguments_;
ager@chromium.org5c838252010-02-19 08:53:10 +0000822 Register name_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000823};
824
825
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000826void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
827 Label* label,
828 Handle<Name> name) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000829 if (!label->is_unused()) {
830 __ bind(label);
831 __ Move(this->name(), name);
832 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000833}
834
835
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000836void StubCompiler::GenerateCheckPropertyCell(MacroAssembler* masm,
837 Handle<JSGlobalObject> global,
838 Handle<Name> name,
839 Register scratch,
840 Label* miss) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000841 Handle<PropertyCell> cell =
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000842 JSGlobalObject::EnsurePropertyCell(global, name);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000843 ASSERT(cell->value()->IsTheHole());
844 __ Move(scratch, cell);
danno@chromium.org41728482013-06-12 22:31:22 +0000845 __ Cmp(FieldOperand(scratch, Cell::kValueOffset),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000846 masm->isolate()->factory()->the_hole_value());
847 __ j(not_equal, miss);
848}
849
850
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000851void StoreStubCompiler::GenerateNegativeHolderLookup(
danno@chromium.orgbee51992013-07-10 14:57:15 +0000852 MacroAssembler* masm,
853 Handle<JSObject> holder,
854 Register holder_reg,
855 Handle<Name> name,
856 Label* miss) {
857 if (holder->IsJSGlobalObject()) {
858 GenerateCheckPropertyCell(
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000859 masm, Handle<JSGlobalObject>::cast(holder), name, scratch1(), miss);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000860 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
861 GenerateDictionaryNegativeLookup(
862 masm, miss, holder_reg, name, scratch1(), scratch2());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000863 }
danno@chromium.orgbee51992013-07-10 14:57:15 +0000864}
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000865
danno@chromium.orgbee51992013-07-10 14:57:15 +0000866
867// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
868// store is successful.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000869void StoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
870 Handle<JSObject> object,
871 LookupResult* lookup,
872 Handle<Map> transition,
873 Handle<Name> name,
874 Register receiver_reg,
875 Register storage_reg,
876 Register value_reg,
877 Register scratch1,
878 Register scratch2,
879 Register unused,
880 Label* miss_label,
881 Label* slow) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000882 int descriptor = transition->LastAdded();
883 DescriptorArray* descriptors = transition->instance_descriptors();
884 PropertyDetails details = descriptors->GetDetails(descriptor);
885 Representation representation = details.representation();
886 ASSERT(!representation.IsNone());
887
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000888 if (details.type() == CONSTANT) {
889 Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate());
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000890 __ Cmp(value_reg, constant);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000891 __ j(not_equal, miss_label);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000892 } else if (FLAG_track_fields && representation.IsSmi()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000893 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000894 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000895 __ JumpIfSmi(value_reg, miss_label);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000896 } else if (FLAG_track_double_fields && representation.IsDouble()) {
897 Label do_store, heap_number;
898 __ AllocateHeapNumber(storage_reg, scratch1, slow);
899
900 __ JumpIfNotSmi(value_reg, &heap_number);
901 __ SmiToInteger32(scratch1, value_reg);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000902 __ Cvtlsi2sd(xmm0, scratch1);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000903 __ jmp(&do_store);
904
905 __ bind(&heap_number);
906 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
danno@chromium.orgbee51992013-07-10 14:57:15 +0000907 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000908 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
909
910 __ bind(&do_store);
911 __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0);
912 }
913
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000914 // Stub never generated for non-global objects that require access
915 // checks.
916 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
917
918 // Perform map transition for the receiver if necessary.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000919 if (details.type() == FIELD &&
920 object->map()->unused_property_fields() == 0) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000921 // The properties must be extended before we can store the value.
922 // We jump to a runtime call that extends the properties array.
danno@chromium.org59400602013-08-13 17:09:37 +0000923 __ PopReturnAddressTo(scratch1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000924 __ push(receiver_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000925 __ Push(transition);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000926 __ push(value_reg);
danno@chromium.org59400602013-08-13 17:09:37 +0000927 __ PushReturnAddressFrom(scratch1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000928 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
930 masm->isolate()),
931 3,
932 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000933 return;
934 }
935
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000936 // Update the map of the object.
937 __ Move(scratch1, transition);
938 __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000939
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000940 // Update the write barrier for the map field.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000941 __ RecordWriteField(receiver_reg,
942 HeapObject::kMapOffset,
943 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000944 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000945 kDontSaveFPRegs,
946 OMIT_REMEMBERED_SET,
947 OMIT_SMI_CHECK);
948
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000949 if (details.type() == CONSTANT) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000950 ASSERT(value_reg.is(rax));
951 __ ret(0);
952 return;
953 }
954
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000955 int index = transition->instance_descriptors()->GetFieldIndex(
956 transition->LastAdded());
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000957
958 // Adjust for the number of properties stored in the object. Even in the
959 // face of a transition we can use the old map here because the size of the
960 // object and the number of in-object properties is not going to change.
961 index -= object->map()->inobject_properties();
962
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000963 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000964 SmiCheck smi_check = representation.IsTagged()
965 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000966 if (index < 0) {
967 // Set the property straight into the object.
968 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000969 if (FLAG_track_double_fields && representation.IsDouble()) {
970 __ movq(FieldOperand(receiver_reg, offset), storage_reg);
971 } else {
972 __ movq(FieldOperand(receiver_reg, offset), value_reg);
973 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000974
danno@chromium.orgf005df62013-04-30 16:36:45 +0000975 if (!FLAG_track_fields || !representation.IsSmi()) {
976 // Update the write barrier for the array address.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000977 if (!FLAG_track_double_fields || !representation.IsDouble()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000978 __ movq(storage_reg, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000979 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000980 __ RecordWriteField(
danno@chromium.orgbee51992013-07-10 14:57:15 +0000981 receiver_reg, offset, storage_reg, scratch1, kDontSaveFPRegs,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000982 EMIT_REMEMBERED_SET, smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000983 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000984 } else {
985 // Write to the properties array.
986 int offset = index * kPointerSize + FixedArray::kHeaderSize;
987 // Get the properties array (optimistically).
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000988 __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000989 if (FLAG_track_double_fields && representation.IsDouble()) {
990 __ movq(FieldOperand(scratch1, offset), storage_reg);
991 } else {
992 __ movq(FieldOperand(scratch1, offset), value_reg);
993 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000994
danno@chromium.orgf005df62013-04-30 16:36:45 +0000995 if (!FLAG_track_fields || !representation.IsSmi()) {
996 // Update the write barrier for the array address.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000997 if (!FLAG_track_double_fields || !representation.IsDouble()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000998 __ movq(storage_reg, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000999 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00001000 __ RecordWriteField(
danno@chromium.orgbee51992013-07-10 14:57:15 +00001001 scratch1, offset, storage_reg, receiver_reg, kDontSaveFPRegs,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001002 EMIT_REMEMBERED_SET, smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001003 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001004 }
1005
1006 // Return the value (register rax).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001007 ASSERT(value_reg.is(rax));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001008 __ ret(0);
1009}
1010
1011
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001012// Both name_reg and receiver_reg are preserved on jumps to miss_label,
1013// but may be destroyed if store is successful.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001014void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
1015 Handle<JSObject> object,
1016 LookupResult* lookup,
1017 Register receiver_reg,
1018 Register name_reg,
1019 Register value_reg,
1020 Register scratch1,
1021 Register scratch2,
1022 Label* miss_label) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001023 // Stub never generated for non-global objects that require access
1024 // checks.
1025 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1026
1027 int index = lookup->GetFieldIndex().field_index();
1028
1029 // Adjust for the number of properties stored in the object. Even in the
1030 // face of a transition we can use the old map here because the size of the
1031 // object and the number of in-object properties is not going to change.
1032 index -= object->map()->inobject_properties();
1033
danno@chromium.orgf005df62013-04-30 16:36:45 +00001034 Representation representation = lookup->representation();
1035 ASSERT(!representation.IsNone());
1036 if (FLAG_track_fields && representation.IsSmi()) {
1037 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001038 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
1039 __ JumpIfSmi(value_reg, miss_label);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001040 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001041 // Load the double storage.
1042 if (index < 0) {
1043 int offset = object->map()->instance_size() + (index * kPointerSize);
1044 __ movq(scratch1, FieldOperand(receiver_reg, offset));
1045 } else {
1046 __ movq(scratch1,
1047 FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
1048 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1049 __ movq(scratch1, FieldOperand(scratch1, offset));
1050 }
1051
1052 // Store the value into the storage.
1053 Label do_store, heap_number;
1054 __ JumpIfNotSmi(value_reg, &heap_number);
1055 __ SmiToInteger32(scratch2, value_reg);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001056 __ Cvtlsi2sd(xmm0, scratch2);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001057 __ jmp(&do_store);
1058
1059 __ bind(&heap_number);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001060 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001061 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001062 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
danno@chromium.orgf005df62013-04-30 16:36:45 +00001063 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001064 __ movsd(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0);
1065 // Return the value (register rax).
1066 ASSERT(value_reg.is(rax));
1067 __ ret(0);
1068 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00001069 }
1070
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001071 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001072 SmiCheck smi_check = representation.IsTagged()
1073 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001074 if (index < 0) {
1075 // Set the property straight into the object.
1076 int offset = object->map()->instance_size() + (index * kPointerSize);
1077 __ movq(FieldOperand(receiver_reg, offset), value_reg);
1078
danno@chromium.orgf005df62013-04-30 16:36:45 +00001079 if (!FLAG_track_fields || !representation.IsSmi()) {
1080 // Update the write barrier for the array address.
1081 // Pass the value being stored in the now unused name_reg.
1082 __ movq(name_reg, value_reg);
1083 __ RecordWriteField(
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001084 receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs,
1085 EMIT_REMEMBERED_SET, smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001086 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001087 } else {
1088 // Write to the properties array.
1089 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1090 // Get the properties array (optimistically).
1091 __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
1092 __ movq(FieldOperand(scratch1, offset), value_reg);
1093
danno@chromium.orgf005df62013-04-30 16:36:45 +00001094 if (!FLAG_track_fields || !representation.IsSmi()) {
1095 // Update the write barrier for the array address.
1096 // Pass the value being stored in the now unused name_reg.
1097 __ movq(name_reg, value_reg);
1098 __ RecordWriteField(
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001099 scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs,
1100 EMIT_REMEMBERED_SET, smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001101 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001102 }
1103
1104 // Return the value (register rax).
1105 ASSERT(value_reg.is(rax));
1106 __ ret(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001107}
1108
1109
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001110void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001111 __ jmp(code, RelocInfo::CODE_TARGET);
1112}
1113
1114
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001115#undef __
1116#define __ ACCESS_MASM((masm()))
1117
1118
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001119Register StubCompiler::CheckPrototypes(Handle<Type> type,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001120 Register object_reg,
1121 Handle<JSObject> holder,
1122 Register holder_reg,
1123 Register scratch1,
1124 Register scratch2,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001125 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001126 int save_at_depth,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001127 Label* miss,
1128 PrototypeCheckType check) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001129 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate()));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001130 // Make sure that the type feedback oracle harvests the receiver map.
1131 // TODO(svenpanne) Remove this hack when all ICs are reworked.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001132 __ Move(scratch1, receiver_map);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001133
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001134 // Make sure there's no overlap between holder and object registers.
1135 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1136 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1137 && !scratch2.is(scratch1));
1138
1139 // Keep track of the current object in register reg. On the first
1140 // iteration, reg is an alias for object_reg, on later iterations,
1141 // it is an alias for holder_reg.
1142 Register reg = object_reg;
1143 int depth = 0;
1144
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001145 StackArgumentsAccessor args(rsp, kFastApiCallArguments,
1146 ARGUMENTS_DONT_CONTAIN_RECEIVER);
1147 const int kHolderIndex = kFastApiCallArguments - 1 -
1148 FunctionCallbackArguments::kHolderIndex;
1149
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001150 if (save_at_depth == depth) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001151 __ movq(args.GetArgumentOperand(kHolderIndex), object_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001152 }
1153
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001154 Handle<JSObject> current = Handle<JSObject>::null();
1155 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant());
1156 Handle<JSObject> prototype = Handle<JSObject>::null();
1157 Handle<Map> current_map = receiver_map;
1158 Handle<Map> holder_map(holder->map());
1159 // Traverse the prototype chain and check the maps in the prototype chain for
1160 // fast and global objects or do negative lookup for normal objects.
1161 while (!current_map.is_identical_to(holder_map)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001162 ++depth;
1163
1164 // Only global objects and objects that do not require access
1165 // checks are allowed in stubs.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001166 ASSERT(current_map->IsJSGlobalProxyMap() ||
1167 !current_map->is_access_check_needed());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001168
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001169 prototype = handle(JSObject::cast(current_map->prototype()));
1170 if (current_map->is_dictionary_map() &&
1171 !current_map->IsJSGlobalObjectMap() &&
1172 !current_map->IsJSGlobalProxyMap()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001173 if (!name->IsUniqueName()) {
1174 ASSERT(name->IsString());
1175 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001176 }
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001177 ASSERT(current.is_null() ||
1178 current->property_dictionary()->FindEntry(*name) ==
ulan@chromium.org750145a2013-03-07 15:14:13 +00001179 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001180
1181 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1182 scratch1, scratch2);
1183
1184 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1185 reg = holder_reg; // From now on the object will be in holder_reg.
1186 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1187 } else {
1188 bool in_new_space = heap()->InNewSpace(*prototype);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001189 if (in_new_space) {
1190 // Save the map in scratch1 for later.
1191 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001192 }
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001193 if (depth != 1 || check == CHECK_ALL_MAPS) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001194 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001195 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001196
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001197 // Check access rights to the global object. This has to happen after
1198 // the map check so that we know that the object is actually a global
1199 // object.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001200 if (current_map->IsJSGlobalProxyMap()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001201 __ CheckAccessGlobalProxy(reg, scratch2, miss);
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001202 } else if (current_map->IsJSGlobalObjectMap()) {
1203 GenerateCheckPropertyCell(
1204 masm(), Handle<JSGlobalObject>::cast(current), name,
1205 scratch2, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001206 }
1207 reg = holder_reg; // From now on the object will be in holder_reg.
1208
1209 if (in_new_space) {
1210 // The prototype is in new space; we cannot store a reference to it
1211 // in the code. Load it from the map.
1212 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1213 } else {
1214 // The prototype is in old space; load it directly.
1215 __ Move(reg, prototype);
1216 }
1217 }
1218
1219 if (save_at_depth == depth) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001220 __ movq(args.GetArgumentOperand(kHolderIndex), reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001221 }
1222
1223 // Go to the next object in the prototype chain.
1224 current = prototype;
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001225 current_map = handle(current->map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001226 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001227
1228 // Log the check depth.
1229 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1230
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001231 if (depth != 0 || check == CHECK_ALL_MAPS) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001232 // Check the holder map.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001233 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001234 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001235
1236 // Perform security check for access to the global object.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001237 ASSERT(current_map->IsJSGlobalProxyMap() ||
1238 !current_map->is_access_check_needed());
1239 if (current_map->IsJSGlobalProxyMap()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001240 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1241 }
1242
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001243 // Return the register containing the holder.
1244 return reg;
1245}
1246
1247
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001248void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001249 if (!miss->is_unused()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001250 Label success;
1251 __ jmp(&success);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001252 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001253 TailCallBuiltin(masm(), MissBuiltin(kind()));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001254 __ bind(&success);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001255 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001256}
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001257
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001258
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001259void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
danno@chromium.orgbee51992013-07-10 14:57:15 +00001260 if (!miss->is_unused()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001261 Label success;
1262 __ jmp(&success);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001263 GenerateRestoreName(masm(), miss, name);
1264 TailCallBuiltin(masm(), MissBuiltin(kind()));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001265 __ bind(&success);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001266 }
1267}
1268
1269
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001270Register LoadStubCompiler::CallbackHandlerFrontend(
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001271 Handle<Type> type,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001272 Register object_reg,
1273 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001274 Handle<Name> name,
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001275 Handle<Object> callback) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001276 Label miss;
1277
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001278 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001279
1280 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1281 ASSERT(!reg.is(scratch2()));
1282 ASSERT(!reg.is(scratch3()));
1283 ASSERT(!reg.is(scratch4()));
1284
1285 // Load the properties dictionary.
1286 Register dictionary = scratch4();
1287 __ movq(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset));
1288
1289 // Probe the dictionary.
1290 Label probe_done;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001291 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1292 &miss,
1293 &probe_done,
1294 dictionary,
1295 this->name(),
1296 scratch2(),
1297 scratch3());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001298 __ bind(&probe_done);
1299
1300 // If probing finds an entry in the dictionary, scratch3 contains the
1301 // index into the dictionary. Check that the value is the callback.
1302 Register index = scratch3();
1303 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +00001304 NameDictionary::kHeaderSize +
1305 NameDictionary::kElementsStartIndex * kPointerSize;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001306 const int kValueOffset = kElementsStartOffset + kPointerSize;
1307 __ movq(scratch2(),
1308 Operand(dictionary, index, times_pointer_size,
1309 kValueOffset - kHeapObjectTag));
1310 __ movq(scratch3(), callback, RelocInfo::EMBEDDED_OBJECT);
1311 __ cmpq(scratch2(), scratch3());
1312 __ j(not_equal, &miss);
1313 }
1314
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001315 HandlerFrontendFooter(name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001316 return reg;
1317}
1318
1319
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001320void LoadStubCompiler::GenerateLoadField(Register reg,
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001321 Handle<JSObject> holder,
1322 PropertyIndex field,
1323 Representation representation) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001324 if (!reg.is(receiver())) __ movq(receiver(), reg);
1325 if (kind() == Code::LOAD_IC) {
1326 LoadFieldStub stub(field.is_inobject(holder),
1327 field.translate(holder),
1328 representation);
1329 GenerateTailCall(masm(), stub.GetCode(isolate()));
1330 } else {
1331 KeyedLoadFieldStub stub(field.is_inobject(holder),
1332 field.translate(holder),
1333 representation);
1334 GenerateTailCall(masm(), stub.GetCode(isolate()));
1335 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001336}
1337
1338
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001339void LoadStubCompiler::GenerateLoadCallback(
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001340 const CallOptimization& call_optimization) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001341 GenerateFastApiCall(
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001342 masm(), call_optimization, receiver(),
1343 scratch1(), scratch2(), name(), 0, NULL);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001344}
1345
1346
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001347void LoadStubCompiler::GenerateLoadCallback(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001348 Register reg,
1349 Handle<ExecutableAccessorInfo> callback) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001350 // Insert additional parameters into the stack frame above return address.
danno@chromium.orgc9db9202013-06-20 13:09:46 +00001351 ASSERT(!scratch4().is(reg));
danno@chromium.org59400602013-08-13 17:09:37 +00001352 __ PopReturnAddressTo(scratch4());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001353
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001354 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
1355 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
1356 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
1357 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
1358 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
1359 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
1360 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001361 __ push(receiver()); // receiver
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001362 if (heap()->InNewSpace(callback->data())) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001363 ASSERT(!scratch2().is(reg));
1364 __ Move(scratch2(), callback);
1365 __ push(FieldOperand(scratch2(),
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001366 ExecutableAccessorInfo::kDataOffset)); // data
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001367 } else {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001368 __ Push(Handle<Object>(callback->data(), isolate()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001369 }
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001370 ASSERT(!kScratchRegister.is(reg));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001371 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
1372 __ push(kScratchRegister); // return value
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001373 __ push(kScratchRegister); // return value default
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001374 __ PushAddress(ExternalReference::isolate_address(isolate()));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001375 __ push(reg); // holder
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001376 __ push(name()); // name
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001377 // Save a pointer to where we pushed the arguments pointer. This will be
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001378 // passed as the const PropertyAccessorInfo& to the C++ callback.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001379
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001380 Address getter_address = v8::ToCData<Address>(callback->getter());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001381
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001382#if defined(__MINGW64__) || defined(_WIN64)
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001383 Register getter_arg = r8;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001384 Register accessor_info_arg = rdx;
1385 Register name_arg = rcx;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001386#else
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001387 Register getter_arg = rdx;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001388 Register accessor_info_arg = rsi;
1389 Register name_arg = rdi;
1390#endif
1391
danno@chromium.orgc9db9202013-06-20 13:09:46 +00001392 ASSERT(!name_arg.is(scratch4()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001393 __ movq(name_arg, rsp);
danno@chromium.org59400602013-08-13 17:09:37 +00001394 __ PushReturnAddressFrom(scratch4());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001395
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001396 // v8::Arguments::values_ and handler for name.
1397 const int kStackSpace = PropertyCallbackArguments::kArgsLength + 1;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001398
1399 // Allocate v8::AccessorInfo in non-GCed stack space.
1400 const int kArgStackSpace = 1;
1401
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001402 __ PrepareCallApiFunction(kArgStackSpace);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001403 __ lea(rax, Operand(name_arg, 1 * kPointerSize));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001404
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001405 // v8::PropertyAccessorInfo::args_.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001406 __ movq(StackSpaceOperand(0), rax);
1407
1408 // The context register (rsi) has been saved in PrepareCallApiFunction and
1409 // could be used to pass arguments.
1410 __ lea(accessor_info_arg, StackSpaceOperand(0));
1411
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001412 Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001413
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001414 // The name handler is counted as an argument.
1415 StackArgumentsAccessor args(rbp, PropertyCallbackArguments::kArgsLength);
1416 Operand return_value_operand = args.GetArgumentOperand(
1417 PropertyCallbackArguments::kArgsLength - 1 -
1418 PropertyCallbackArguments::kReturnValueOffset);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001419 __ CallApiFunctionAndReturn(getter_address,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001420 thunk_address,
1421 getter_arg,
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001422 kStackSpace,
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001423 return_value_operand,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001424 NULL);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001425}
1426
1427
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001428void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001429 // Return the constant value.
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00001430 __ Move(rax, value);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001431 __ ret(0);
1432}
1433
1434
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001435void LoadStubCompiler::GenerateLoadInterceptor(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001436 Register holder_reg,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001437 Handle<Object> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001438 Handle<JSObject> interceptor_holder,
1439 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001440 Handle<Name> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001441 ASSERT(interceptor_holder->HasNamedInterceptor());
1442 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1443
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001444 // So far the most popular follow ups for interceptor loads are FIELD
1445 // and CALLBACKS, so inline only them, other cases may be added
1446 // later.
1447 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001448 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001449 if (lookup->IsField()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001450 compile_followup_inline = true;
1451 } else if (lookup->type() == CALLBACKS &&
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001452 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1453 ExecutableAccessorInfo* callback =
1454 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001455 compile_followup_inline = callback->getter() != NULL &&
1456 callback->IsCompatibleReceiver(*object);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001457 }
1458 }
1459
1460 if (compile_followup_inline) {
1461 // Compile the interceptor call, followed by inline code to load the
1462 // property from further up the prototype chain if the call fails.
1463 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001464 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001465
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001466 // Preserve the receiver register explicitly whenever it is different from
1467 // the holder and it is needed should the interceptor return without any
1468 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1469 // the FIELD case might cause a miss during the prototype check.
1470 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001471 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001472 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1473
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001474 // Save necessary data before invoking an interceptor.
1475 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001476 {
1477 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001478
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001479 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001480 __ push(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001481 }
1482 __ push(holder_reg);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001483 __ push(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001484
1485 // Invoke an interceptor. Note: map checks from receiver to
1486 // interceptor's holder has been compiled before (see a caller
1487 // of this method.)
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001488 CompileCallLoadPropertyWithInterceptor(
1489 masm(), receiver(), holder_reg, this->name(), interceptor_holder,
1490 IC::kLoadPropertyWithInterceptorOnly);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001491
1492 // Check if interceptor provided a value for property. If it's
1493 // the case, return immediately.
1494 Label interceptor_failed;
1495 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
1496 __ j(equal, &interceptor_failed);
1497 frame_scope.GenerateLeaveFrame();
1498 __ ret(0);
1499
1500 __ bind(&interceptor_failed);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001501 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001502 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001503 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001504 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001505 }
1506
1507 // Leave the internal frame.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001508 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001509
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001510 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001511 } else { // !compile_followup_inline
1512 // Call the runtime system to load the interceptor.
1513 // Check that the maps haven't changed.
danno@chromium.org59400602013-08-13 17:09:37 +00001514 __ PopReturnAddressTo(scratch2());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001515 PushInterceptorArguments(masm(), receiver(), holder_reg,
1516 this->name(), interceptor_holder);
danno@chromium.org59400602013-08-13 17:09:37 +00001517 __ PushReturnAddressFrom(scratch2());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001518
1519 ExternalReference ref = ExternalReference(
lrn@chromium.org7516f052011-03-30 08:52:27 +00001520 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001521 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001522 }
1523}
1524
1525
ulan@chromium.org750145a2013-03-07 15:14:13 +00001526void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001527 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001528 __ Cmp(rcx, name);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001529 __ j(not_equal, miss);
1530 }
1531}
1532
1533
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001534void CallStubCompiler::GenerateFunctionCheck(Register function,
1535 Register scratch,
1536 Label* miss) {
1537 __ JumpIfSmi(function, miss);
1538 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch);
1539 __ j(not_equal, miss);
1540}
1541
1542
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001543void CallStubCompiler::GenerateLoadFunctionFromCell(
danno@chromium.org41728482013-06-12 22:31:22 +00001544 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001545 Handle<JSFunction> function,
1546 Label* miss) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001547 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001548 __ Move(rdi, cell);
danno@chromium.org41728482013-06-12 22:31:22 +00001549 __ movq(rdi, FieldOperand(rdi, Cell::kValueOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001550
1551 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001552 if (heap()->InNewSpace(*function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001553 // We can't embed a pointer to a function in new space so we have
1554 // to verify that the shared function info is unchanged. This has
1555 // the nice side effect that multiple closures based on the same
1556 // function can all use this call IC. Before we load through the
1557 // function, we have to verify that it still is a function.
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001558 GenerateFunctionCheck(rdi, rax, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001559
1560 // Check the shared function info. Make sure it hasn't changed.
1561 __ Move(rax, Handle<SharedFunctionInfo>(function->shared()));
1562 __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001563 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001564 __ Cmp(rdi, function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001565 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001566 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001567}
1568
1569
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001570void CallStubCompiler::GenerateMissBranch() {
1571 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001572 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1573 kind_,
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00001574 extra_state());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001575 __ Jump(code, RelocInfo::CODE_TARGET);
1576}
1577
1578
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001579Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1580 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001581 PropertyIndex index,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001582 Handle<Name> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001583 Label miss;
1584
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001585 Register reg = HandlerFrontendHeader(
1586 object, holder, name, RECEIVER_MAP_CHECK, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001587
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001588 GenerateFastPropertyLoad(masm(), rdi, reg, index.is_inobject(holder),
1589 index.translate(holder), Representation::Tagged());
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001590 GenerateJumpFunction(object, rdi, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001591
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001592 HandlerFrontendFooter(&miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001593
1594 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00001595 return GetCode(Code::FAST, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001596}
1597
1598
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001599Handle<Code> CallStubCompiler::CompileArrayCodeCall(
1600 Handle<Object> object,
1601 Handle<JSObject> holder,
1602 Handle<Cell> cell,
1603 Handle<JSFunction> function,
1604 Handle<String> name,
1605 Code::StubType type) {
1606 Label miss;
1607
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001608 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
1609 if (!cell.is_null()) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001610 ASSERT(cell->value() == *function);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001611 GenerateLoadFunctionFromCell(cell, function, &miss);
1612 }
1613
danno@chromium.orgbee51992013-07-10 14:57:15 +00001614 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001615 site->SetElementsKind(GetInitialFastElementsKind());
danno@chromium.orgbee51992013-07-10 14:57:15 +00001616 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site);
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001617 const int argc = arguments().immediate();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001618 __ movq(rax, Immediate(argc));
danno@chromium.orgbee51992013-07-10 14:57:15 +00001619 __ Move(rbx, site_feedback_cell);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001620 __ Move(rdi, function);
1621
1622 ArrayConstructorStub stub(isolate());
1623 __ TailCallStub(&stub);
1624
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001625 HandlerFrontendFooter(&miss);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001626
1627 // Return the generated code.
1628 return GetCode(type, name);
1629}
1630
1631
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001632Handle<Code> CallStubCompiler::CompileArrayPushCall(
1633 Handle<Object> object,
1634 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00001635 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001636 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001637 Handle<String> name,
1638 Code::StubType type) {
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001639 // If object is not an array or is observed or sealed, bail out to regular
1640 // call.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001641 if (!object->IsJSArray() ||
1642 !cell.is_null() ||
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001643 Handle<JSArray>::cast(object)->map()->is_observed() ||
1644 !Handle<JSArray>::cast(object)->map()->is_extensible()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001645 return Handle<Code>::null();
1646 }
ager@chromium.orgac091b72010-05-05 07:34:42 +00001647
1648 Label miss;
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001649
1650 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001651
ager@chromium.orgac091b72010-05-05 07:34:42 +00001652 const int argc = arguments().immediate();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001653 StackArgumentsAccessor args(rsp, argc);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001654 if (argc == 0) {
1655 // Noop, return the length.
1656 __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset));
1657 __ ret((argc + 1) * kPointerSize);
1658 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001659 Label call_builtin;
1660
ager@chromium.orgac091b72010-05-05 07:34:42 +00001661 if (argc == 1) { // Otherwise fall through to call builtin.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001662 Label attempt_to_grow_elements, with_write_barrier, check_double;
ager@chromium.orgac091b72010-05-05 07:34:42 +00001663
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001664 // Get the elements array of the object.
1665 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
1666
1667 // Check that the elements are in fast mode and writable.
1668 __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
1669 factory()->fixed_array_map());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001670 __ j(not_equal, &check_double);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001671
ager@chromium.orgac091b72010-05-05 07:34:42 +00001672 // Get the array's length into rax and calculate new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001673 __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001674 STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001675 __ addl(rax, Immediate(argc));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001676
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001677 // Get the elements' length into rcx.
1678 __ SmiToInteger32(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001679
1680 // Check if we could survive without allocation.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001681 __ cmpl(rax, rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001682 __ j(greater, &attempt_to_grow_elements);
1683
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001684 // Check if value is a smi.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001685 __ movq(rcx, args.GetArgumentOperand(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001686 __ JumpIfNotSmi(rcx, &with_write_barrier);
1687
ager@chromium.orgac091b72010-05-05 07:34:42 +00001688 // Save new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001689 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001690
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001691 // Store the value.
1692 __ movq(FieldOperand(rdi,
1693 rax,
1694 times_pointer_size,
1695 FixedArray::kHeaderSize - argc * kPointerSize),
1696 rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001697
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001698 __ Integer32ToSmi(rax, rax); // Return new length as smi.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001699 __ ret((argc + 1) * kPointerSize);
1700
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001701 __ bind(&check_double);
1702
1703 // Check that the elements are in double mode.
1704 __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
1705 factory()->fixed_double_array_map());
1706 __ j(not_equal, &call_builtin);
1707
1708 // Get the array's length into rax and calculate new length.
1709 __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset));
1710 STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue);
1711 __ addl(rax, Immediate(argc));
1712
1713 // Get the elements' length into rcx.
1714 __ SmiToInteger32(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
1715
1716 // Check if we could survive without allocation.
1717 __ cmpl(rax, rcx);
1718 __ j(greater, &call_builtin);
1719
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001720 __ movq(rcx, args.GetArgumentOperand(1));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001721 __ StoreNumberToDoubleElements(
1722 rcx, rdi, rax, xmm0, &call_builtin, argc * kDoubleSize);
1723
1724 // Save new length.
1725 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
1726 __ Integer32ToSmi(rax, rax); // Return new length as smi.
1727 __ ret((argc + 1) * kPointerSize);
1728
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001729 __ bind(&with_write_barrier);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001730
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001731 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
1732
1733 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1734 Label fast_object, not_fast_object;
1735 __ CheckFastObjectElements(rbx, &not_fast_object, Label::kNear);
1736 __ jmp(&fast_object);
1737 // In case of fast smi-only, convert to fast object, otherwise bail out.
1738 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001739 __ CheckFastSmiElements(rbx, &call_builtin);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001740 __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset),
1741 factory()->heap_number_map());
1742 __ j(equal, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001743 // rdx: receiver
1744 // rbx: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001745
1746 Label try_holey_map;
1747 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001748 FAST_ELEMENTS,
1749 rbx,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001750 rdi,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001751 &try_holey_map);
1752
1753 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001754 GenerateMapChangeElementsTransition(masm(),
1755 DONT_TRACK_ALLOCATION_SITE,
1756 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001757 // Restore edi.
1758 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
1759 __ jmp(&fast_object);
1760
1761 __ bind(&try_holey_map);
1762 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1763 FAST_HOLEY_ELEMENTS,
1764 rbx,
1765 rdi,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001766 &call_builtin);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001767 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001768 GenerateMapChangeElementsTransition(masm(),
1769 DONT_TRACK_ALLOCATION_SITE,
1770 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001771 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001772 __ bind(&fast_object);
1773 } else {
1774 __ CheckFastObjectElements(rbx, &call_builtin);
1775 }
1776
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001777 // Save new length.
1778 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001779
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001780 // Store the value.
1781 __ lea(rdx, FieldOperand(rdi,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001782 rax, times_pointer_size,
1783 FixedArray::kHeaderSize - argc * kPointerSize));
1784 __ movq(Operand(rdx, 0), rcx);
1785
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001786 __ RecordWrite(rdi, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001787 OMIT_SMI_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001788
1789 __ Integer32ToSmi(rax, rax); // Return new length as smi.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001790 __ ret((argc + 1) * kPointerSize);
1791
1792 __ bind(&attempt_to_grow_elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001793 if (!FLAG_inline_new) {
1794 __ jmp(&call_builtin);
1795 }
1796
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001797 __ movq(rbx, args.GetArgumentOperand(1));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001798 // Growing elements that are SMI-only requires special handling in case
1799 // the new element is non-Smi. For now, delegate to the builtin.
1800 Label no_fast_elements_check;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001801 __ JumpIfSmi(rbx, &no_fast_elements_check);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001802 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
1803 __ CheckFastObjectElements(rcx, &call_builtin, Label::kFar);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001804 __ bind(&no_fast_elements_check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001805
ager@chromium.orgac091b72010-05-05 07:34:42 +00001806 ExternalReference new_space_allocation_top =
lrn@chromium.org7516f052011-03-30 08:52:27 +00001807 ExternalReference::new_space_allocation_top_address(isolate());
ager@chromium.orgac091b72010-05-05 07:34:42 +00001808 ExternalReference new_space_allocation_limit =
lrn@chromium.org7516f052011-03-30 08:52:27 +00001809 ExternalReference::new_space_allocation_limit_address(isolate());
ager@chromium.orgac091b72010-05-05 07:34:42 +00001810
1811 const int kAllocationDelta = 4;
1812 // Load top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001813 __ Load(rcx, new_space_allocation_top);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001814
1815 // Check if it's the end of elements.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001816 __ lea(rdx, FieldOperand(rdi,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001817 rax, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001818 FixedArray::kHeaderSize - argc * kPointerSize));
1819 __ cmpq(rdx, rcx);
1820 __ j(not_equal, &call_builtin);
1821 __ addq(rcx, Immediate(kAllocationDelta * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001822 Operand limit_operand =
1823 masm()->ExternalOperand(new_space_allocation_limit);
1824 __ cmpq(rcx, limit_operand);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001825 __ j(above, &call_builtin);
1826
1827 // We fit and could grow elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001828 __ Store(new_space_allocation_top, rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001829
1830 // Push the argument...
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001831 __ movq(Operand(rdx, 0), rbx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001832 // ... and fill the rest with holes.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001833 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001834 for (int i = 1; i < kAllocationDelta; i++) {
1835 __ movq(Operand(rdx, i * kPointerSize), kScratchRegister);
1836 }
1837
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001838 // We know the elements array is in new space so we don't need the
1839 // remembered set, but we just pushed a value onto it so we may have to
1840 // tell the incremental marker to rescan the object that we just grew. We
1841 // don't need to worry about the holes because they are in old space and
1842 // already marked black.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001843 __ RecordWrite(rdi, rdx, rbx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001844
ager@chromium.orgac091b72010-05-05 07:34:42 +00001845 // Restore receiver to rdx as finish sequence assumes it's here.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001846 __ movq(rdx, args.GetReceiverOperand());
ager@chromium.orgac091b72010-05-05 07:34:42 +00001847
1848 // Increment element's and array's sizes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001849 __ SmiAddConstant(FieldOperand(rdi, FixedArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001850 Smi::FromInt(kAllocationDelta));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001851
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001852 // Make new length a smi before returning it.
1853 __ Integer32ToSmi(rax, rax);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001854 __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001855
ager@chromium.orgac091b72010-05-05 07:34:42 +00001856 __ ret((argc + 1) * kPointerSize);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001857 }
1858
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001859 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001860 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001861 isolate()),
ager@chromium.orgac091b72010-05-05 07:34:42 +00001862 argc + 1,
1863 1);
1864 }
1865
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001866 HandlerFrontendFooter(&miss);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001867
1868 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001869 return GetCode(type, name);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001870}
1871
1872
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001873Handle<Code> CallStubCompiler::CompileArrayPopCall(
1874 Handle<Object> object,
1875 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00001876 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001877 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001878 Handle<String> name,
1879 Code::StubType type) {
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001880 // If object is not an array or is observed or sealed, bail out to regular
1881 // call.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001882 if (!object->IsJSArray() ||
1883 !cell.is_null() ||
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001884 Handle<JSArray>::cast(object)->map()->is_observed() ||
1885 !Handle<JSArray>::cast(object)->map()->is_extensible()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001886 return Handle<Code>::null();
1887 }
ager@chromium.orgac091b72010-05-05 07:34:42 +00001888
1889 Label miss, return_undefined, call_builtin;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001890
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001891 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001892
1893 // Get the elements array of the object.
1894 __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
1895
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001896 // Check that the elements are in fast mode and writable.
1897 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
1898 Heap::kFixedArrayMapRootIndex);
1899 __ j(not_equal, &call_builtin);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001900
1901 // Get the array's length into rcx and calculate new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001902 __ SmiToInteger32(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
1903 __ subl(rcx, Immediate(1));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001904 __ j(negative, &return_undefined);
1905
1906 // Get the last element.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001907 __ LoadRoot(r9, Heap::kTheHoleValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001908 __ movq(rax, FieldOperand(rbx,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001909 rcx, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001910 FixedArray::kHeaderSize));
1911 // Check if element is already the hole.
1912 __ cmpq(rax, r9);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001913 // If so, call slow-case to also check prototypes for value.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001914 __ j(equal, &call_builtin);
1915
1916 // Set the array's length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001917 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001918
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001919 // Fill with the hole and return original value.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001920 __ movq(FieldOperand(rbx,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001921 rcx, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001922 FixedArray::kHeaderSize),
1923 r9);
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001924 const int argc = arguments().immediate();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001925 __ ret((argc + 1) * kPointerSize);
1926
1927 __ bind(&return_undefined);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001928 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001929 __ ret((argc + 1) * kPointerSize);
1930
1931 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001932 __ TailCallExternalReference(
lrn@chromium.org7516f052011-03-30 08:52:27 +00001933 ExternalReference(Builtins::c_ArrayPop, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001934 argc + 1,
1935 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001936
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001937 HandlerFrontendFooter(&miss);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001938
1939 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001940 return GetCode(type, name);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001941}
1942
1943
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001944Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1945 Handle<Object> object,
1946 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00001947 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001948 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001949 Handle<String> name,
1950 Code::StubType type) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001951 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001952 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001953
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001954 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001955 Label name_miss;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001956 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001957 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001958 if (kind_ == Code::CALL_IC &&
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00001959 (CallICBase::StringStubState::decode(extra_state()) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001960 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001961 index_out_of_range_label = &miss;
1962 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001963
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001964 HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001965
1966 Register receiver = rbx;
1967 Register index = rdi;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001968 Register result = rax;
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001969 const int argc = arguments().immediate();
1970 StackArgumentsAccessor args(rsp, argc);
1971
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001972 __ movq(receiver, args.GetReceiverOperand());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001973 if (argc > 0) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001974 __ movq(index, args.GetArgumentOperand(1));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001975 } else {
1976 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1977 }
1978
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001979 StringCharCodeAtGenerator generator(receiver,
1980 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001981 result,
1982 &miss, // When not a string.
1983 &miss, // When not a number.
1984 index_out_of_range_label,
1985 STRING_INDEX_IS_NUMBER);
1986 generator.GenerateFast(masm());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001987 __ ret((argc + 1) * kPointerSize);
1988
1989 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001990 generator.GenerateSlow(masm(), call_helper);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001991
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001992 if (index_out_of_range.is_linked()) {
1993 __ bind(&index_out_of_range);
1994 __ LoadRoot(rax, Heap::kNanValueRootIndex);
1995 __ ret((argc + 1) * kPointerSize);
1996 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001997
1998 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001999 // Restore function name in rcx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002000 __ Move(rcx, name);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002001 HandlerFrontendFooter(&name_miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002002
2003 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002004 return GetCode(type, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002005}
2006
2007
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002008Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2009 Handle<Object> object,
2010 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002011 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002012 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002013 Handle<String> name,
2014 Code::StubType type) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002015 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002016 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002017
2018 const int argc = arguments().immediate();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002019 StackArgumentsAccessor args(rsp, argc);
2020
ricow@chromium.org65fae842010-08-25 15:26:24 +00002021 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002022 Label name_miss;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002023 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002024 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002025 if (kind_ == Code::CALL_IC &&
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00002026 (CallICBase::StringStubState::decode(extra_state()) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002027 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002028 index_out_of_range_label = &miss;
2029 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002030
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002031 HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002032
2033 Register receiver = rax;
2034 Register index = rdi;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002035 Register scratch = rdx;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002036 Register result = rax;
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002037 __ movq(receiver, args.GetReceiverOperand());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002038 if (argc > 0) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002039 __ movq(index, args.GetArgumentOperand(1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002040 } else {
2041 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2042 }
2043
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002044 StringCharAtGenerator generator(receiver,
2045 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002046 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002047 result,
2048 &miss, // When not a string.
2049 &miss, // When not a number.
2050 index_out_of_range_label,
2051 STRING_INDEX_IS_NUMBER);
2052 generator.GenerateFast(masm());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002053 __ ret((argc + 1) * kPointerSize);
2054
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002055 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002056 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002057
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002058 if (index_out_of_range.is_linked()) {
2059 __ bind(&index_out_of_range);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002060 __ LoadRoot(rax, Heap::kempty_stringRootIndex);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002061 __ ret((argc + 1) * kPointerSize);
2062 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002063 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002064 // Restore function name in rcx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002065 __ Move(rcx, name);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002066 HandlerFrontendFooter(&name_miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002067
2068 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002069 return GetCode(type, name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002070}
2071
2072
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002073Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2074 Handle<Object> object,
2075 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002076 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002077 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002078 Handle<String> name,
2079 Code::StubType type) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002080 // If the object is not a JSObject or we got an unexpected number of
2081 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002082 const int argc = arguments().immediate();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002083 StackArgumentsAccessor args(rsp, argc);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002084 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002085
2086 Label miss;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002087
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002088 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
2089 if (!cell.is_null()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002090 ASSERT(cell->value() == *function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002091 GenerateLoadFunctionFromCell(cell, function, &miss);
2092 }
2093
2094 // Load the char code argument.
2095 Register code = rbx;
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002096 __ movq(code, args.GetArgumentOperand(1));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002097
2098 // Check the code is a smi.
2099 Label slow;
2100 __ JumpIfNotSmi(code, &slow);
2101
2102 // Convert the smi code to uint16.
2103 __ SmiAndConstant(code, code, Smi::FromInt(0xffff));
2104
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002105 StringCharFromCodeGenerator generator(code, rax);
2106 generator.GenerateFast(masm());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002107 __ ret(2 * kPointerSize);
2108
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002109 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002110 generator.GenerateSlow(masm(), call_helper);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002111
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002112 __ bind(&slow);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002113 // We do not have to patch the receiver because the function makes no use of
2114 // it.
2115 GenerateJumpFunctionIgnoreReceiver(function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002116
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002117 HandlerFrontendFooter(&miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002118
2119 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002120 return GetCode(type, name);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002121}
2122
2123
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002124Handle<Code> CallStubCompiler::CompileMathFloorCall(
2125 Handle<Object> object,
2126 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002127 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002128 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002129 Handle<String> name,
2130 Code::StubType type) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002131 const int argc = arguments().immediate();
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002132 StackArgumentsAccessor args(rsp, argc);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002133
2134 // If the object is not a JSObject or we got an unexpected number of
2135 // arguments, bail out to the regular call.
2136 if (!object->IsJSObject() || argc != 1) {
2137 return Handle<Code>::null();
2138 }
2139
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002140 Label miss, slow;
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002141
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002142 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
2143 if (!cell.is_null()) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002144 ASSERT(cell->value() == *function);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002145 GenerateLoadFunctionFromCell(cell, function, &miss);
2146 }
2147
2148 // Load the (only) argument into rax.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002149 __ movq(rax, args.GetArgumentOperand(1));
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002150
2151 // Check if the argument is a smi.
2152 Label smi;
2153 STATIC_ASSERT(kSmiTag == 0);
2154 __ JumpIfSmi(rax, &smi);
2155
2156 // Check if the argument is a heap number and load its value into xmm0.
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002157 __ CheckMap(rax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
2158 __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
2159
2160 // Check if the argument is strictly positive. Note this also discards NaN.
2161 __ xorpd(xmm1, xmm1);
2162 __ ucomisd(xmm0, xmm1);
2163 __ j(below_equal, &slow);
2164
2165 // Do a truncating conversion.
2166 __ cvttsd2si(rax, xmm0);
2167
2168 // Checks for 0x80000000 which signals a failed conversion.
2169 Label conversion_failure;
2170 __ cmpl(rax, Immediate(0x80000000));
2171 __ j(equal, &conversion_failure);
2172
2173 // Smi tag and return.
2174 __ Integer32ToSmi(rax, rax);
2175 __ bind(&smi);
2176 __ ret(2 * kPointerSize);
2177
2178 // Check if the argument is < 2^kMantissaBits.
2179 Label already_round;
2180 __ bind(&conversion_failure);
2181 int64_t kTwoMantissaBits= V8_INT64_C(0x4330000000000000);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002182 __ movq(rbx, kTwoMantissaBits);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002183 __ movq(xmm1, rbx);
2184 __ ucomisd(xmm0, xmm1);
2185 __ j(above_equal, &already_round);
2186
2187 // Save a copy of the argument.
2188 __ movaps(xmm2, xmm0);
2189
2190 // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits.
2191 __ addsd(xmm0, xmm1);
2192 __ subsd(xmm0, xmm1);
2193
2194 // Compare the argument and the tentative result to get the right mask:
2195 // if xmm2 < xmm0:
2196 // xmm2 = 1...1
2197 // else:
2198 // xmm2 = 0...0
2199 __ cmpltsd(xmm2, xmm0);
2200
2201 // Subtract 1 if the argument was less than the tentative result.
2202 int64_t kOne = V8_INT64_C(0x3ff0000000000000);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002203 __ movq(rbx, kOne);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002204 __ movq(xmm1, rbx);
2205 __ andpd(xmm1, xmm2);
2206 __ subsd(xmm0, xmm1);
2207
2208 // Return a new heap number.
2209 __ AllocateHeapNumber(rax, rbx, &slow);
2210 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0);
2211 __ ret(2 * kPointerSize);
2212
2213 // Return the argument (when it's an already round heap number).
2214 __ bind(&already_round);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002215 __ movq(rax, args.GetArgumentOperand(1));
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002216 __ ret(2 * kPointerSize);
2217
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002218 __ bind(&slow);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002219 // We do not have to patch the receiver because the function makes no use of
2220 // it.
2221 GenerateJumpFunctionIgnoreReceiver(function);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002222
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002223 HandlerFrontendFooter(&miss);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002224
2225 // Return the generated code.
2226 return GetCode(type, name);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002227}
2228
2229
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002230Handle<Code> CallStubCompiler::CompileMathAbsCall(
2231 Handle<Object> object,
2232 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002233 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002234 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002235 Handle<String> name,
2236 Code::StubType type) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002237 // If the object is not a JSObject or we got an unexpected number of
2238 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002239 const int argc = arguments().immediate();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002240 StackArgumentsAccessor args(rsp, argc);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002241 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002242
2243 Label miss;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002244
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002245 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
2246 if (!cell.is_null()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002247 ASSERT(cell->value() == *function);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002248 GenerateLoadFunctionFromCell(cell, function, &miss);
2249 }
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002250
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002251 // Load the (only) argument into rax.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002252 __ movq(rax, args.GetArgumentOperand(1));
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002253
2254 // Check if the argument is a smi.
2255 Label not_smi;
2256 STATIC_ASSERT(kSmiTag == 0);
2257 __ JumpIfNotSmi(rax, &not_smi);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002258
danno@chromium.org59400602013-08-13 17:09:37 +00002259 // Branchless abs implementation, refer to below:
2260 // http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002261 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2262 // otherwise.
danno@chromium.org59400602013-08-13 17:09:37 +00002263 __ movq(rbx, rax);
2264 __ sar(rbx, Immediate(kBitsPerPointer - 1));
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002265
2266 // Do bitwise not or do nothing depending on ebx.
danno@chromium.org59400602013-08-13 17:09:37 +00002267 __ xor_(rax, rbx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002268
2269 // Add 1 or do nothing depending on ebx.
danno@chromium.org59400602013-08-13 17:09:37 +00002270 __ subq(rax, rbx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002271
2272 // If the result is still negative, go to the slow case.
2273 // This only happens for the most negative smi.
2274 Label slow;
2275 __ j(negative, &slow);
2276
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002277 __ ret(2 * kPointerSize);
2278
2279 // Check if the argument is a heap number and load its value.
2280 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002281 __ CheckMap(rax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
bmeurer@chromium.orge94b5ff2013-10-25 09:22:31 +00002282 __ MoveDouble(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002283
2284 // Check the sign of the argument. If the argument is positive,
2285 // just return it.
2286 Label negative_sign;
2287 const int sign_mask_shift =
2288 (HeapNumber::kExponentOffset - HeapNumber::kValueOffset) * kBitsPerByte;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002289 __ Set(rdi, static_cast<int64_t>(HeapNumber::kSignMask) << sign_mask_shift);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002290 __ testq(rbx, rdi);
2291 __ j(not_zero, &negative_sign);
2292 __ ret(2 * kPointerSize);
2293
2294 // If the argument is negative, clear the sign, and return a new
2295 // number. We still have the sign mask in rdi.
2296 __ bind(&negative_sign);
2297 __ xor_(rbx, rdi);
2298 __ AllocateHeapNumber(rax, rdx, &slow);
bmeurer@chromium.orge94b5ff2013-10-25 09:22:31 +00002299 __ MoveDouble(FieldOperand(rax, HeapNumber::kValueOffset), rbx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002300 __ ret(2 * kPointerSize);
2301
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002302 __ bind(&slow);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002303 // We do not have to patch the receiver because the function makes no use of
2304 // it.
2305 GenerateJumpFunctionIgnoreReceiver(function);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002306
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002307 HandlerFrontendFooter(&miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002308
2309 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002310 return GetCode(type, name);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002311}
2312
2313
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002314Handle<Code> CallStubCompiler::CompileFastApiCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002315 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002316 Handle<Object> object,
2317 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002318 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002319 Handle<JSFunction> function,
2320 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002321 ASSERT(optimization.is_simple_api_call());
2322 // Bail out if object is a global object as we don't want to
2323 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002324 if (object->IsGlobalObject()) return Handle<Code>::null();
2325 if (!cell.is_null()) return Handle<Code>::null();
2326 if (!object->IsJSObject()) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002327 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002328 Handle<JSObject>::cast(object), holder);
2329 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002330
2331 Label miss, miss_before_stack_reserved;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002332 GenerateNameCheck(name, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002333
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002334 const int argc = arguments().immediate();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002335 StackArgumentsAccessor args(rsp, argc);
2336 __ movq(rdx, args.GetReceiverOperand());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002337
2338 // Check that the receiver isn't a smi.
2339 __ JumpIfSmi(rdx, &miss_before_stack_reserved);
2340
lrn@chromium.org7516f052011-03-30 08:52:27 +00002341 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002342 __ IncrementCounter(counters->call_const(), 1);
2343 __ IncrementCounter(counters->call_const_fast_api(), 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002344
2345 // Allocate space for v8::Arguments implicit values. Must be initialized
2346 // before calling any runtime function.
2347 __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2348
2349 // Check that the maps haven't changed and find a Holder as a side effect.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002350 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder,
2351 rbx, rax, rdi, name, depth, &miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002352
2353 // Move the return address on top of the stack.
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002354 __ movq(rax,
2355 StackOperandForReturnAddress(kFastApiCallArguments * kPointerSize));
2356 __ movq(StackOperandForReturnAddress(0), rax);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002357
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00002358 GenerateFastApiCall(masm(), optimization, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002359
2360 __ bind(&miss);
2361 __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2362
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002363 HandlerFrontendFooter(&miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002364
2365 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002366 return GetCode(function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002367}
2368
2369
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002370void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
2371 Label success;
2372 // Check that the object is a boolean.
2373 __ CompareRoot(object, Heap::kTrueValueRootIndex);
2374 __ j(equal, &success);
2375 __ CompareRoot(object, Heap::kFalseValueRootIndex);
2376 __ j(not_equal, miss);
2377 __ bind(&success);
2378}
2379
2380
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002381void CallStubCompiler::PatchGlobalProxy(Handle<Object> object) {
2382 if (object->IsGlobalObject()) {
2383 StackArgumentsAccessor args(rsp, arguments());
2384 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
2385 __ movq(args.GetReceiverOperand(), rdx);
2386 }
2387}
2388
2389
2390Register CallStubCompiler::HandlerFrontendHeader(Handle<Object> object,
2391 Handle<JSObject> holder,
2392 Handle<Name> name,
2393 CheckType check,
2394 Label* miss) {
2395 GenerateNameCheck(name, miss);
2396
2397 Register reg = rdx;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002398
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002399 StackArgumentsAccessor args(rsp, arguments());
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002400 __ movq(reg, args.GetReceiverOperand());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002401
2402 // Check that the receiver isn't a smi.
2403 if (check != NUMBER_CHECK) {
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002404 __ JumpIfSmi(reg, miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002405 }
2406
2407 // Make sure that it's okay not to patch the on stack receiver
2408 // unless we're doing a receiver map check.
2409 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2410
lrn@chromium.org7516f052011-03-30 08:52:27 +00002411 Counters* counters = isolate()->counters();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002412 switch (check) {
2413 case RECEIVER_MAP_CHECK:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002414 __ IncrementCounter(counters->call_const(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002415
2416 // Check that the maps haven't changed.
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002417 reg = CheckPrototypes(IC::CurrentTypeOf(object, isolate()), reg, holder,
2418 rbx, rax, rdi, name, miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002419 break;
2420
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002421 case STRING_CHECK: {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002422 // Check that the object is a string.
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002423 __ CmpObjectType(reg, FIRST_NONSTRING_TYPE, rax);
2424 __ j(above_equal, miss);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002425 // Check that the maps starting from the prototype haven't changed.
2426 GenerateDirectLoadGlobalFunctionPrototype(
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002427 masm(), Context::STRING_FUNCTION_INDEX, rax, miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002428 break;
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002429 }
2430 case SYMBOL_CHECK: {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002431 // Check that the object is a symbol.
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002432 __ CmpObjectType(reg, SYMBOL_TYPE, rax);
2433 __ j(not_equal, miss);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002434 // Check that the maps starting from the prototype haven't changed.
2435 GenerateDirectLoadGlobalFunctionPrototype(
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002436 masm(), Context::SYMBOL_FUNCTION_INDEX, rax, miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002437 break;
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002438 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002439 case NUMBER_CHECK: {
2440 Label fast;
2441 // Check that the object is a smi or a heap number.
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002442 __ JumpIfSmi(reg, &fast);
2443 __ CmpObjectType(reg, HEAP_NUMBER_TYPE, rax);
2444 __ j(not_equal, miss);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002445 __ bind(&fast);
2446 // Check that the maps starting from the prototype haven't changed.
2447 GenerateDirectLoadGlobalFunctionPrototype(
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002448 masm(), Context::NUMBER_FUNCTION_INDEX, rax, miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002449 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002450 }
2451 case BOOLEAN_CHECK: {
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002452 GenerateBooleanCheck(reg, miss);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002453 // Check that the maps starting from the prototype haven't changed.
2454 GenerateDirectLoadGlobalFunctionPrototype(
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002455 masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002456 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002457 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002458 }
2459
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002460 if (check != RECEIVER_MAP_CHECK) {
2461 Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
2462 reg = CheckPrototypes(
2463 IC::CurrentTypeOf(prototype, isolate()),
2464 rax, holder, rbx, rdx, rdi, name, miss);
2465 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002466
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002467 return reg;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002468}
2469
2470
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002471void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
2472 Register function,
2473 Label* miss) {
2474 // Check that the function really is a function.
2475 GenerateFunctionCheck(function, rbx, miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002476
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002477 if (!function.is(rdi)) __ movq(rdi, function);
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002478 PatchGlobalProxy(object);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002479
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002480 // Invoke the function.
2481 __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
2482 NullCallWrapper(), call_kind());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002483}
2484
2485
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002486Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2487 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002488 Handle<Name> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002489 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002490 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002491
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002492 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002493 LookupPostInterceptor(holder, name, &lookup);
2494
2495 // Get the receiver from the stack.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002496 StackArgumentsAccessor args(rsp, arguments());
2497 __ movq(rdx, args.GetReceiverOperand());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002498
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00002499 CallInterceptorCompiler compiler(this, arguments(), rcx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002500 compiler.Compile(masm(), object, holder, name, &lookup, rdx, rbx, rdi, rax,
2501 &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002502
2503 // Restore receiver.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002504 __ movq(rdx, args.GetReceiverOperand());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002505
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002506 GenerateJumpFunction(object, rax, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002507
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002508 HandlerFrontendFooter(&miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002509
2510 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00002511 return GetCode(Code::FAST, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002512}
2513
2514
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002515Handle<Code> CallStubCompiler::CompileCallGlobal(
2516 Handle<JSObject> object,
2517 Handle<GlobalObject> holder,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002518 Handle<PropertyCell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002519 Handle<JSFunction> function,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002520 Handle<Name> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002521 if (HasCustomCallGenerator(function)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002522 Handle<Code> code = CompileCustomCall(
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002523 object, holder, cell, function, Handle<String>::cast(name),
2524 Code::NORMAL);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002525 // A null handle means bail out to the regular compiler code below.
2526 if (!code.is_null()) return code;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002527 }
2528
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002529 Label miss;
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002530 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002531 // Potentially loads a closure that matches the shared function info of the
2532 // function, rather than function.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002533 GenerateLoadFunctionFromCell(cell, function, &miss);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002534 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002535 __ IncrementCounter(counters->call_global_inline(), 1);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002536 GenerateJumpFunction(object, rdi, function);
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002537 HandlerFrontendFooter(&miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002538
2539 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002540 return GetCode(Code::NORMAL, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002541}
2542
2543
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002544Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002545 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002546 Handle<JSObject> holder,
danno@chromium.orgbee51992013-07-10 14:57:15 +00002547 Handle<Name> name,
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002548 Handle<ExecutableAccessorInfo> callback) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002549 HandlerFrontend(IC::CurrentTypeOf(object, isolate()),
2550 receiver(), holder, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002551
danno@chromium.org59400602013-08-13 17:09:37 +00002552 __ PopReturnAddressTo(scratch1());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002553 __ push(receiver());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002554 __ Push(callback); // callback info
danno@chromium.orgbee51992013-07-10 14:57:15 +00002555 __ Push(name);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002556 __ push(value());
danno@chromium.org59400602013-08-13 17:09:37 +00002557 __ PushReturnAddressFrom(scratch1());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002558
2559 // Do tail-call to the runtime system.
2560 ExternalReference store_callback_property =
lrn@chromium.org7516f052011-03-30 08:52:27 +00002561 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002562 __ TailCallExternalReference(store_callback_property, 4, 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002563
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002564 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00002565 return GetCode(kind(), Code::FAST, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002566}
2567
2568
dslomov@chromium.org639bac02013-09-09 11:58:54 +00002569Handle<Code> StoreStubCompiler::CompileStoreCallback(
2570 Handle<JSObject> object,
2571 Handle<JSObject> holder,
2572 Handle<Name> name,
2573 const CallOptimization& call_optimization) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002574 HandlerFrontend(IC::CurrentTypeOf(object, isolate()),
2575 receiver(), holder, name);
dslomov@chromium.org639bac02013-09-09 11:58:54 +00002576
2577 Register values[] = { value() };
2578 GenerateFastApiCall(
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00002579 masm(), call_optimization, receiver(), scratch1(),
2580 scratch2(), this->name(), 1, values);
dslomov@chromium.org639bac02013-09-09 11:58:54 +00002581
2582 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00002583 return GetCode(kind(), Code::FAST, name);
dslomov@chromium.org639bac02013-09-09 11:58:54 +00002584}
2585
2586
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002587#undef __
2588#define __ ACCESS_MASM(masm)
2589
2590
2591void StoreStubCompiler::GenerateStoreViaSetter(
2592 MacroAssembler* masm,
2593 Handle<JSFunction> setter) {
2594 // ----------- S t a t e -------------
2595 // -- rax : value
2596 // -- rcx : name
2597 // -- rdx : receiver
2598 // -- rsp[0] : return address
2599 // -----------------------------------
2600 {
2601 FrameScope scope(masm, StackFrame::INTERNAL);
2602
2603 // Save value register, so we can restore it later.
2604 __ push(rax);
2605
2606 if (!setter.is_null()) {
2607 // Call the JavaScript setter with receiver and value on the stack.
2608 __ push(rdx);
2609 __ push(rax);
2610 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002611 ParameterCount expected(setter);
2612 __ InvokeFunction(setter, expected, actual,
2613 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002614 } else {
2615 // If we generate a global code snippet for deoptimization only, remember
2616 // the place to continue after deoptimization.
2617 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2618 }
2619
2620 // We have to return the passed value, not the return value of the setter.
2621 __ pop(rax);
2622
2623 // Restore context register.
2624 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2625 }
2626 __ ret(0);
2627}
2628
2629
2630#undef __
2631#define __ ACCESS_MASM(masm())
2632
2633
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002634Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002635 Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002636 Handle<Name> name) {
danno@chromium.org59400602013-08-13 17:09:37 +00002637 __ PopReturnAddressTo(scratch1());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002638 __ push(receiver());
2639 __ push(this->name());
2640 __ push(value());
danno@chromium.org59400602013-08-13 17:09:37 +00002641 __ PushReturnAddressFrom(scratch1());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002642
2643 // Do tail-call to the runtime system.
2644 ExternalReference store_ic_property =
lrn@chromium.org7516f052011-03-30 08:52:27 +00002645 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002646 __ TailCallExternalReference(store_ic_property, 3, 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002647
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002648 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00002649 return GetCode(kind(), Code::FAST, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002650}
2651
2652
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002653Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2654 MapHandleList* receiver_maps,
2655 CodeHandleList* handler_stubs,
2656 MapHandleList* transitioned_maps) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002657 Label miss;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002658 __ JumpIfSmi(receiver(), &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002659
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002660 __ movq(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002661 int receiver_count = receiver_maps->length();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002662 for (int i = 0; i < receiver_count; ++i) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002663 // Check map and tail call if there's a match
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002664 __ Cmp(scratch1(), receiver_maps->at(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002665 if (transitioned_maps->at(i).is_null()) {
2666 __ j(equal, handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002667 } else {
2668 Label next_map;
2669 __ j(not_equal, &next_map, Label::kNear);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002670 __ movq(transition_map(),
2671 transitioned_maps->at(i),
2672 RelocInfo::EMBEDDED_OBJECT);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002673 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002674 __ bind(&next_map);
2675 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002676 }
2677
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002678 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002679
2680 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002681
2682 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002683 return GetICCode(
2684 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002685}
2686
2687
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002688Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<Type> type,
2689 Handle<JSObject> last,
2690 Handle<Name> name) {
2691 NonexistentHandlerFrontend(type, last, name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002692
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002693 // Return undefined if maps of the full prototype chain are still the
2694 // same and no global property with this name contains a value.
2695 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2696 __ ret(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002697
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002698 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00002699 return GetCode(kind(), Code::FAST, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002700}
2701
2702
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002703Register* LoadStubCompiler::registers() {
2704 // receiver, name, scratch1, scratch2, scratch3, scratch4.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002705 static Register registers[] = { rax, rcx, rdx, rbx, rdi, r8 };
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002706 return registers;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002707}
2708
2709
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002710Register* KeyedLoadStubCompiler::registers() {
2711 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2712 static Register registers[] = { rdx, rax, rbx, rcx, rdi, r8 };
2713 return registers;
2714}
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002715
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002716
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002717Register* StoreStubCompiler::registers() {
2718 // receiver, name, value, scratch1, scratch2, scratch3.
2719 static Register registers[] = { rdx, rcx, rax, rbx, rdi, r8 };
2720 return registers;
2721}
2722
2723
2724Register* KeyedStoreStubCompiler::registers() {
2725 // receiver, name, value, scratch1, scratch2, scratch3.
2726 static Register registers[] = { rdx, rcx, rax, rbx, rdi, r8 };
2727 return registers;
2728}
2729
2730
ulan@chromium.org750145a2013-03-07 15:14:13 +00002731void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002732 Register name_reg,
2733 Label* miss) {
2734 __ Cmp(name_reg, name);
2735 __ j(not_equal, miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002736}
2737
2738
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002739void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
2740 Register name_reg,
2741 Label* miss) {
2742 __ Cmp(name_reg, name);
2743 __ j(not_equal, miss);
2744}
2745
2746
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002747#undef __
2748#define __ ACCESS_MASM(masm)
2749
2750
2751void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00002752 Register receiver,
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002753 Handle<JSFunction> getter) {
2754 // ----------- S t a t e -------------
2755 // -- rax : receiver
2756 // -- rcx : name
2757 // -- rsp[0] : return address
2758 // -----------------------------------
2759 {
2760 FrameScope scope(masm, StackFrame::INTERNAL);
2761
2762 if (!getter.is_null()) {
2763 // Call the JavaScript getter with the receiver on the stack.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00002764 __ push(receiver);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002765 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002766 ParameterCount expected(getter);
2767 __ InvokeFunction(getter, expected, actual,
2768 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002769 } else {
2770 // If we generate a global code snippet for deoptimization only, remember
2771 // the place to continue after deoptimization.
2772 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2773 }
2774
2775 // Restore context register.
2776 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2777 }
2778 __ ret(0);
2779}
2780
2781
2782#undef __
2783#define __ ACCESS_MASM(masm())
2784
2785
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002786Handle<Code> LoadStubCompiler::CompileLoadGlobal(
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002787 Handle<Type> type,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002788 Handle<GlobalObject> global,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002789 Handle<PropertyCell> cell,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002790 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002791 bool is_dont_delete) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002792 Label miss;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002793 // TODO(verwaest): Directly store to rax. Currently we cannot do this, since
2794 // rax is used as receiver(), which we would otherwise clobber before a
2795 // potential miss.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002796 HandlerFrontendHeader(type, receiver(), global, name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002797
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002798 // Get the value from the cell.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002799 __ Move(rbx, cell);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002800 __ movq(rbx, FieldOperand(rbx, PropertyCell::kValueOffset));
whesse@chromium.orge90029b2010-08-02 11:52:17 +00002801
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002802 // Check for deleted property if property can actually be deleted.
2803 if (!is_dont_delete) {
2804 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
2805 __ j(equal, &miss);
2806 } else if (FLAG_debug_code) {
2807 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
danno@chromium.org59400602013-08-13 17:09:37 +00002808 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002809 }
2810
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002811 HandlerFrontendFooter(name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002812
lrn@chromium.org7516f052011-03-30 08:52:27 +00002813 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002814 __ IncrementCounter(counters->named_load_global_stub(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002815 __ movq(rax, rbx);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002816 __ ret(0);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002817
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002818 // Return the generated code.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002819 return GetCode(kind(), Code::NORMAL, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002820}
2821
2822
danno@chromium.orgbee51992013-07-10 14:57:15 +00002823Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002824 TypeHandleList* types,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002825 CodeHandleList* handlers,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002826 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002827 Code::StubType type,
2828 IcCheckType check) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002829 Label miss;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002830
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002831 if (check == PROPERTY) {
2832 GenerateNameCheck(name, this->name(), &miss);
2833 }
2834
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002835 Label number_case;
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002836 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002837 __ JumpIfSmi(receiver(), smi_target);
2838
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002839 Register map_reg = scratch1();
2840 __ movq(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002841 int receiver_count = types->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00002842 int number_of_handled_maps = 0;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002843 for (int current = 0; current < receiver_count; ++current) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002844 Handle<Type> type = types->at(current);
2845 Handle<Map> map = IC::TypeToMap(*type, isolate());
danno@chromium.orgf005df62013-04-30 16:36:45 +00002846 if (!map->is_deprecated()) {
2847 number_of_handled_maps++;
2848 // Check map and tail call if there's a match
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002849 __ Cmp(map_reg, map);
2850 if (type->Is(Type::Number())) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002851 ASSERT(!number_case.is_unused());
2852 __ bind(&number_case);
2853 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002854 __ j(equal, handlers->at(current), RelocInfo::CODE_TARGET);
2855 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002856 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002857 ASSERT(number_of_handled_maps > 0);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002858
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002859 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002860 TailCallBuiltin(masm(), MissBuiltin(kind()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002861
2862 // Return the generated code.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002863 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00002864 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
ulan@chromium.org750145a2013-03-07 15:14:13 +00002865 return GetICCode(kind(), type, name, state);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002866}
2867
2868
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002869#undef __
2870#define __ ACCESS_MASM(masm)
2871
2872
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002873void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
2874 MacroAssembler* masm) {
2875 // ----------- S t a t e -------------
2876 // -- rax : key
2877 // -- rdx : receiver
2878 // -- rsp[0] : return address
2879 // -----------------------------------
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002880 Label slow, miss;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002881
2882 // This stub is meant to be tail-jumped to, the receiver must already
2883 // have been verified by the caller to not be a smi.
2884
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002885 __ JumpIfNotSmi(rax, &miss);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002886 __ SmiToInteger32(rbx, rax);
2887 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
2888
2889 // Check whether the elements is a number dictionary.
2890 // rdx: receiver
2891 // rax: key
2892 // rbx: key as untagged int32
2893 // rcx: elements
2894 __ LoadFromNumberDictionary(&slow, rcx, rax, rbx, r9, rdi, rax);
2895 __ ret(0);
2896
2897 __ bind(&slow);
2898 // ----------- S t a t e -------------
2899 // -- rax : key
2900 // -- rdx : receiver
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00002901 // -- rsp[0] : return address
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002902 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002903 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002904
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002905 __ bind(&miss);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002906 // ----------- S t a t e -------------
2907 // -- rax : key
2908 // -- rdx : receiver
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00002909 // -- rsp[0] : return address
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002910 // -----------------------------------
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002911 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002912}
2913
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002914
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002915#undef __
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002916
2917} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002918
2919#endif // V8_TARGET_ARCH_X64