blob: 94650fd49a28483023572ca79a94d9b4adf4a873 [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
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000110// Helper function used to check that the dictionary doesn't contain
111// the property. This function may return false negatives, so miss_label
112// must always call a backup property check that is complete.
113// This function is safe to call if the receiver has fast properties.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000114// Name must be unique and receiver must be a heap object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000115static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
116 Label* miss_label,
117 Register receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000118 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000119 Register r0,
120 Register r1) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000121 ASSERT(name->IsUniqueName());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000122 Counters* counters = masm->isolate()->counters();
123 __ IncrementCounter(counters->negative_lookups(), 1);
124 __ IncrementCounter(counters->negative_lookups_miss(), 1);
125
126 __ movq(r0, FieldOperand(receiver, HeapObject::kMapOffset));
127
128 const int kInterceptorOrAccessCheckNeededMask =
129 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
130
131 // Bail out if the receiver has a named interceptor or requires access checks.
132 __ testb(FieldOperand(r0, Map::kBitFieldOffset),
133 Immediate(kInterceptorOrAccessCheckNeededMask));
134 __ j(not_zero, miss_label);
135
136 // Check that receiver is a JSObject.
137 __ CmpInstanceType(r0, FIRST_SPEC_OBJECT_TYPE);
138 __ j(below, miss_label);
139
140 // Load properties array.
141 Register properties = r0;
142 __ movq(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
143
144 // Check that the properties array is a dictionary.
145 __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset),
146 Heap::kHashTableMapRootIndex);
147 __ j(not_equal, miss_label);
148
149 Label done;
ulan@chromium.org750145a2013-03-07 15:14:13 +0000150 NameDictionaryLookupStub::GenerateNegativeLookup(masm,
151 miss_label,
152 &done,
153 properties,
154 name,
155 r1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000156 __ bind(&done);
157 __ DecrementCounter(counters->negative_lookups_miss(), 1);
158}
159
160
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000161void StubCache::GenerateProbe(MacroAssembler* masm,
162 Code::Flags flags,
163 Register receiver,
164 Register name,
165 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000166 Register extra,
ulan@chromium.org812308e2012-02-29 15:58:45 +0000167 Register extra2,
168 Register extra3) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000169 Isolate* isolate = masm->isolate();
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000170 Label miss;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000171 USE(extra); // The register extra is not used on the X64 platform.
172 USE(extra2); // The register extra2 is not used on the X64 platform.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000173 USE(extra3); // The register extra2 is not used on the X64 platform.
174 // Make sure that code is valid. The multiplying code relies on the
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000175 // entry size being 3 * kPointerSize.
176 ASSERT(sizeof(Entry) == 3 * kPointerSize);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000177
178 // Make sure the flags do not name a specific type.
179 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
180
181 // Make sure that there are no register conflicts.
182 ASSERT(!scratch.is(receiver));
183 ASSERT(!scratch.is(name));
184
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000185 // Check scratch register is valid, extra and extra2 are unused.
186 ASSERT(!scratch.is(no_reg));
187 ASSERT(extra2.is(no_reg));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000188 ASSERT(extra3.is(no_reg));
189
190 Counters* counters = masm->isolate()->counters();
191 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000192
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000193 // Check that the receiver isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000194 __ JumpIfSmi(receiver, &miss);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000195
196 // Get the map of the receiver and compute the hash.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000197 __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000198 // Use only the low 32 bits of the map pointer.
199 __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
200 __ xor_(scratch, Immediate(flags));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000201 // We mask out the last two bits because they are not part of the hash and
202 // they are always 01 for maps. Also in the two 'and' instructions below.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000203 __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
204
205 // Probe the primary table.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000206 ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000207
208 // Primary miss: Compute hash for secondary probe.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000209 __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000210 __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
211 __ xor_(scratch, Immediate(flags));
212 __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
213 __ subl(scratch, name);
214 __ addl(scratch, Immediate(flags));
215 __ and_(scratch, Immediate((kSecondaryTableSize - 1) << kHeapObjectTagSize));
216
217 // Probe the secondary table.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000218 ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000219
220 // Cache miss: Fall-through and let caller handle the miss by
221 // entering the runtime system.
222 __ bind(&miss);
ulan@chromium.org812308e2012-02-29 15:58:45 +0000223 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000224}
225
226
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000227void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
228 int index,
229 Register prototype) {
230 // Load the global or builtins object from the current context.
231 __ movq(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000232 Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
233 // Load the native context from the global or builtins object.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000234 __ movq(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000235 FieldOperand(prototype, GlobalObject::kNativeContextOffset));
236 // Load the function from the native context.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000237 __ movq(prototype, Operand(prototype, Context::SlotOffset(index)));
238 // Load the initial map. The global functions all have initial maps.
239 __ movq(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000240 FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000241 // Load the prototype from the initial map.
242 __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
243}
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000244
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000245
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000246void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000247 MacroAssembler* masm,
248 int index,
249 Register prototype,
250 Label* miss) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000251 Isolate* isolate = masm->isolate();
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000252 // Check we're still in the same context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000253 __ Move(prototype, isolate->global_object());
254 __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)),
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000255 prototype);
256 __ j(not_equal, miss);
257 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000258 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000259 JSFunction::cast(isolate->native_context()->get(index)));
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000260 // Load its initial map. The global functions all have initial maps.
261 __ Move(prototype, Handle<Map>(function->initial_map()));
262 // Load the prototype from the initial map.
263 __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000264}
265
266
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000267void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
268 Register receiver,
269 Register scratch,
270 Label* miss_label) {
271 // Check that the receiver isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000272 __ JumpIfSmi(receiver, miss_label);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000273
274 // Check that the object is a JS array.
275 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
276 __ j(not_equal, miss_label);
277
278 // Load length directly from the JS array.
279 __ movq(rax, FieldOperand(receiver, JSArray::kLengthOffset));
280 __ ret(0);
281}
282
283
284// Generate code to check if an object is a string. If the object is
285// a string, the map's instance type is left in the scratch register.
286static void GenerateStringCheck(MacroAssembler* masm,
287 Register receiver,
288 Register scratch,
289 Label* smi,
290 Label* non_string_object) {
291 // Check that the object isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000292 __ JumpIfSmi(receiver, smi);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000293
294 // Check that the object is a string.
295 __ movq(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
296 __ movzxbq(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000297 STATIC_ASSERT(kNotStringTag != 0);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000298 __ testl(scratch, Immediate(kNotStringTag));
299 __ j(not_zero, non_string_object);
300}
301
302
303void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
304 Register receiver,
ager@chromium.org5c838252010-02-19 08:53:10 +0000305 Register scratch1,
306 Register scratch2,
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000307 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000308 Label check_wrapper;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000309
310 // Check if the object is a string leaving the instance type in the
311 // scratch register.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000312 GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000313
314 // Load length directly from the string.
ager@chromium.orgac091b72010-05-05 07:34:42 +0000315 __ movq(rax, FieldOperand(receiver, String::kLengthOffset));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000316 __ ret(0);
317
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000318 // Check if the object is a JSValue wrapper.
319 __ bind(&check_wrapper);
320 __ cmpl(scratch1, Immediate(JS_VALUE_TYPE));
321 __ j(not_equal, miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000322
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000323 // Check if the wrapped value is a string and load the length
324 // directly if it is.
325 __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
326 GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
327 __ movq(rax, FieldOperand(scratch2, String::kLengthOffset));
328 __ ret(0);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000329}
330
331
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000332void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
333 Register receiver,
334 Register result,
335 Register scratch,
336 Label* miss_label) {
337 __ TryGetFunctionPrototype(receiver, result, miss_label);
338 if (!result.is(rax)) __ movq(rax, result);
339 __ ret(0);
340}
341
342
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000343void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
344 Register dst,
345 Register src,
346 bool inobject,
347 int index,
348 Representation representation) {
349 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000350 int offset = index * kPointerSize;
351 if (!inobject) {
352 // Calculate the offset into the properties array.
353 offset = offset + FixedArray::kHeaderSize;
354 __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
355 src = dst;
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000356 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000357 __ movq(dst, FieldOperand(src, offset));
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000358}
359
360
361static void PushInterceptorArguments(MacroAssembler* masm,
362 Register receiver,
363 Register holder,
364 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000365 Handle<JSObject> holder_obj) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000366 STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0);
367 STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1);
368 STATIC_ASSERT(StubCache::kInterceptorArgsThisIndex == 2);
369 STATIC_ASSERT(StubCache::kInterceptorArgsHolderIndex == 3);
370 STATIC_ASSERT(StubCache::kInterceptorArgsLength == 4);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000371 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000372 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
373 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
374 __ Move(kScratchRegister, interceptor);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000375 __ push(kScratchRegister);
376 __ push(receiver);
377 __ push(holder);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000378}
379
380
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000381static void CompileCallLoadPropertyWithInterceptor(
382 MacroAssembler* masm,
383 Register receiver,
384 Register holder,
385 Register name,
386 Handle<JSObject> holder_obj) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000387 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
388
389 ExternalReference ref =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000390 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
391 masm->isolate());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000392 __ Set(rax, StubCache::kInterceptorArgsLength);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000393 __ LoadAddress(rbx, ref);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000394
ager@chromium.orga1645e22009-09-09 19:27:10 +0000395 CEntryStub stub(1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000396 __ CallStub(&stub);
397}
398
399
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000400// Number of pointers to be reserved on stack for fast API call.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000401static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000402
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000403
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000404// Reserves space for the extra arguments to API function in the
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000405// caller's frame.
406//
407// These arguments are set by CheckPrototypes and GenerateFastApiCall.
408static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
409 // ----------- S t a t e -------------
410 // -- rsp[0] : return address
411 // -- rsp[8] : last argument in the internal frame of the caller
412 // -----------------------------------
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000413 __ movq(scratch, StackOperandForReturnAddress(0));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000414 __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000415 __ movq(StackOperandForReturnAddress(0), scratch);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000416 __ Move(scratch, Smi::FromInt(0));
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000417 StackArgumentsAccessor args(rsp, kFastApiCallArguments,
418 ARGUMENTS_DONT_CONTAIN_RECEIVER);
419 for (int i = 0; i < kFastApiCallArguments; i++) {
420 __ movq(args.GetArgumentOperand(i), scratch);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000421 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000422}
423
424
425// Undoes the effects of ReserveSpaceForFastApiCall.
426static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
427 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +0000428 // -- rsp[0] : return address.
429 // -- rsp[8] : last fast api call extra argument.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000430 // -- ...
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +0000431 // -- rsp[kFastApiCallArguments * 8] : first fast api call extra
432 // argument.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000433 // -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal
434 // frame.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000435 // -----------------------------------
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000436 __ movq(scratch, StackOperandForReturnAddress(0));
437 __ movq(StackOperandForReturnAddress(kFastApiCallArguments * kPointerSize),
438 scratch);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000439 __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000440}
441
442
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000443// Generates call to API function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000444static void GenerateFastApiCall(MacroAssembler* masm,
445 const CallOptimization& optimization,
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000446 int argc,
447 bool restore_context) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000448 // ----------- S t a t e -------------
449 // -- rsp[0] : return address
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000450 // -- rsp[8] - rsp[56] : FunctionCallbackInfo, incl.
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000451 // : object passing the type check
452 // (set by CheckPrototypes)
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000453 // -- rsp[64] : last argument
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000454 // -- ...
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000455 // -- rsp[(argc + 7) * 8] : first argument
456 // -- rsp[(argc + 8) * 8] : receiver
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000457 // -----------------------------------
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000458 typedef FunctionCallbackArguments FCA;
459 StackArgumentsAccessor args(rsp, argc + kFastApiCallArguments);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000460
461 // Save calling context.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000462 int offset = argc + kFastApiCallArguments;
463 __ movq(args.GetArgumentOperand(offset - FCA::kContextSaveIndex), rsi);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000464
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000465 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000466 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000467 __ LoadHeapObject(rdi, function);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000468 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000469 // Construct the FunctionCallbackInfo on the stack.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000470 __ movq(args.GetArgumentOperand(offset - FCA::kCalleeIndex), rdi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000471 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000472 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000473 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
474 __ Move(rcx, api_call_info);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000475 __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000476 __ movq(args.GetArgumentOperand(offset - FCA::kDataIndex), rbx);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000477 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000478 __ Move(args.GetArgumentOperand(offset - FCA::kDataIndex), call_data);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000479 }
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000480 __ movq(kScratchRegister,
481 ExternalReference::isolate_address(masm->isolate()));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000482 __ movq(args.GetArgumentOperand(offset - FCA::kIsolateIndex),
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000483 kScratchRegister);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000484 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000485 __ movq(args.GetArgumentOperand(offset - FCA::kReturnValueDefaultValueIndex),
486 kScratchRegister);
487 __ movq(args.GetArgumentOperand(offset - FCA::kReturnValueOffset),
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000488 kScratchRegister);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000489
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000490 // Prepare arguments.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000491 STATIC_ASSERT(kFastApiCallArguments == 7);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000492 __ lea(rbx, Operand(rsp, 1 * kPointerSize));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000493
494 // Function address is a foreign pointer outside V8's heap.
495 Address function_address = v8::ToCData<Address>(api_call_info->callback());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000496
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000497 // Allocate the v8::Arguments structure in the arguments' space since
498 // it's not controlled by GC.
499 const int kApiStackSpace = 4;
500
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000501 __ PrepareCallApiFunction(kApiStackSpace);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000502
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000503 __ movq(StackSpaceOperand(0), rbx); // FunctionCallbackInfo::implicit_args_.
504 __ addq(rbx, Immediate((argc + kFastApiCallArguments - 1) * kPointerSize));
505 __ movq(StackSpaceOperand(1), rbx); // FunctionCallbackInfo::values_.
506 __ Set(StackSpaceOperand(2), argc); // FunctionCallbackInfo::length_.
507 // FunctionCallbackInfo::is_construct_call_.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000508 __ Set(StackSpaceOperand(3), 0);
509
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000510#if defined(__MINGW64__) || defined(_WIN64)
511 Register arguments_arg = rcx;
512 Register callback_arg = rdx;
513#else
514 Register arguments_arg = rdi;
515 Register callback_arg = rsi;
516#endif
517
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000518 // v8::InvocationCallback's argument.
519 __ lea(arguments_arg, StackSpaceOperand(0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000520
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000521 Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000522
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000523 StackArgumentsAccessor args_from_rbp(rbp, kFastApiCallArguments,
524 ARGUMENTS_DONT_CONTAIN_RECEIVER);
525 Operand context_restore_operand = args_from_rbp.GetArgumentOperand(
526 kFastApiCallArguments - 1 - FCA::kContextSaveIndex);
527 Operand return_value_operand = args_from_rbp.GetArgumentOperand(
528 kFastApiCallArguments - 1 - FCA::kReturnValueOffset);
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000529 __ CallApiFunctionAndReturn(
530 function_address,
531 thunk_address,
532 callback_arg,
533 argc + kFastApiCallArguments + 1,
534 return_value_operand,
535 restore_context ? &context_restore_operand : NULL);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000536}
537
538
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000539// Generate call to api function.
540static void GenerateFastApiCall(MacroAssembler* masm,
541 const CallOptimization& optimization,
542 Register receiver,
543 Register scratch,
544 int argc,
545 Register* values) {
546 ASSERT(optimization.is_simple_api_call());
547 ASSERT(!receiver.is(scratch));
548
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000549 const int fast_api_call_argc = argc + kFastApiCallArguments;
550 StackArgumentsAccessor args(rsp, fast_api_call_argc);
551 // argc + 1 is the argument number before FastApiCall arguments, 1 ~ receiver
552 const int kHolderIndex = argc + 1 +
553 kFastApiCallArguments - 1 - FunctionCallbackArguments::kHolderIndex;
554 __ movq(scratch, StackOperandForReturnAddress(0));
555 // Assign stack space for the call arguments and receiver.
556 __ subq(rsp, Immediate((fast_api_call_argc + 1) * kPointerSize));
557 __ movq(StackOperandForReturnAddress(0), scratch);
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000558 // Write holder to stack frame.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000559 __ movq(args.GetArgumentOperand(kHolderIndex), receiver);
560 __ movq(args.GetReceiverOperand(), receiver);
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000561 // Write the arguments to stack frame.
562 for (int i = 0; i < argc; i++) {
563 ASSERT(!receiver.is(values[i]));
564 ASSERT(!scratch.is(values[i]));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000565 __ movq(args.GetArgumentOperand(i + 1), values[i]);
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000566 }
567
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000568 GenerateFastApiCall(masm, optimization, argc, true);
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000569}
570
571
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000572class CallInterceptorCompiler BASE_EMBEDDED {
573 public:
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000574 CallInterceptorCompiler(StubCompiler* stub_compiler,
575 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000576 Register name,
577 Code::ExtraICState extra_ic_state)
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000578 : stub_compiler_(stub_compiler),
579 arguments_(arguments),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000580 name_(name),
581 extra_ic_state_(extra_ic_state) {}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000582
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000583 void Compile(MacroAssembler* masm,
584 Handle<JSObject> object,
585 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000586 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000587 LookupResult* lookup,
588 Register receiver,
589 Register scratch1,
590 Register scratch2,
591 Register scratch3,
592 Label* miss) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000593 ASSERT(holder->HasNamedInterceptor());
594 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
595
596 // Check that the receiver isn't a smi.
597 __ JumpIfSmi(receiver, miss);
598
599 CallOptimization optimization(lookup);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000600 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000601 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
602 holder, lookup, name, optimization, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000603 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000604 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
605 name, holder, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000606 }
607 }
608
609 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000610 void CompileCacheable(MacroAssembler* masm,
611 Handle<JSObject> object,
612 Register receiver,
613 Register scratch1,
614 Register scratch2,
615 Register scratch3,
616 Handle<JSObject> interceptor_holder,
617 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000618 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000619 const CallOptimization& optimization,
620 Label* miss_label) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000621 ASSERT(optimization.is_constant_call());
ager@chromium.org5c838252010-02-19 08:53:10 +0000622 ASSERT(!lookup->holder()->IsGlobalObject());
623
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000624 int depth1 = kInvalidProtoDepth;
625 int depth2 = kInvalidProtoDepth;
626 bool can_do_fast_api_call = false;
627 if (optimization.is_simple_api_call() &&
628 !lookup->holder()->IsGlobalObject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000629 depth1 = optimization.GetPrototypeDepthOfExpectedType(
630 object, interceptor_holder);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000631 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000632 depth2 = optimization.GetPrototypeDepthOfExpectedType(
633 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000634 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000635 can_do_fast_api_call =
636 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000637 }
638
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000639 Counters* counters = masm->isolate()->counters();
640 __ IncrementCounter(counters->call_const_interceptor(), 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000641
642 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000643 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000644 ReserveSpaceForFastApiCall(masm, scratch1);
645 }
646
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000647 // Check that the maps from receiver to interceptor's holder
648 // haven't changed and thus we can invoke interceptor.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000649 Label miss_cleanup;
650 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
651 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000652 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
653 scratch1, scratch2, scratch3,
654 name, depth1, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000655
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000656 // Invoke an interceptor and if it provides a value,
657 // branch to |regular_invoke|.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000658 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000659 LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
660 &regular_invoke);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000661
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000662 // Interceptor returned nothing for this property. Try to use cached
663 // constant function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000664
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000665 // Check that the maps from interceptor's holder to constant function's
666 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000667 if (*interceptor_holder != lookup->holder()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000668 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000669 Handle<JSObject>(lookup->holder()),
670 scratch1, scratch2, scratch3,
671 name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000672 } else {
673 // CheckPrototypes has a side effect of fetching a 'holder'
674 // for API (object which is instanceof for the signature). It's
675 // safe to omit it here, as if present, it should be fetched
676 // by the previous CheckPrototypes.
677 ASSERT(depth2 == kInvalidProtoDepth);
678 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000679
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000680 // Invoke function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000681 if (can_do_fast_api_call) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000682 GenerateFastApiCall(masm, optimization, arguments_.immediate(), false);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000683 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000684 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
685 ? CALL_AS_FUNCTION
686 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000687 Handle<JSFunction> fun = optimization.constant_function();
ulan@chromium.orgbebf0742013-04-24 12:21:36 +0000688 ParameterCount expected(fun);
689 __ InvokeFunction(fun, expected, arguments_,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000690 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000691 }
692
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000693 // Deferred code for fast API call case---clean preallocated space.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000694 if (can_do_fast_api_call) {
695 __ bind(&miss_cleanup);
696 FreeSpaceForFastApiCall(masm, scratch1);
697 __ jmp(miss_label);
698 }
699
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000700 // Invoke a regular function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000701 __ bind(&regular_invoke);
702 if (can_do_fast_api_call) {
703 FreeSpaceForFastApiCall(masm, scratch1);
704 }
705 }
706
707 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000708 Handle<JSObject> object,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000709 Register receiver,
710 Register scratch1,
711 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000712 Register scratch3,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000713 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000714 Handle<JSObject> interceptor_holder,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000715 Label* miss_label) {
716 Register holder =
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000717 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000718 scratch1, scratch2, scratch3,
719 name, miss_label);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000720
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000721 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000722 // Save the name_ register across the call.
723 __ push(name_);
724
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000725 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000726
727 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000728 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
729 masm->isolate()),
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000730 StubCache::kInterceptorArgsLength);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000731
732 // Restore the name_ register.
733 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000734
735 // Leave the internal frame.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000736 }
737
738 void LoadWithInterceptor(MacroAssembler* masm,
739 Register receiver,
740 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000741 Handle<JSObject> holder_obj,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000742 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000743 {
744 FrameScope scope(masm, StackFrame::INTERNAL);
745 __ push(holder); // Save the holder.
746 __ push(name_); // Save the name.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000747
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000748 CompileCallLoadPropertyWithInterceptor(masm,
749 receiver,
750 holder,
751 name_,
752 holder_obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000753
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000754 __ pop(name_); // Restore the name.
755 __ pop(receiver); // Restore the holder.
756 // Leave the internal frame.
757 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000758
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000759 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000760 __ j(not_equal, interceptor_succeeded);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000761 }
762
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000763 StubCompiler* stub_compiler_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000764 const ParameterCount& arguments_;
ager@chromium.org5c838252010-02-19 08:53:10 +0000765 Register name_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000766 Code::ExtraICState extra_ic_state_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000767};
768
769
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000770void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
771 Label* label,
772 Handle<Name> name) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000773 if (!label->is_unused()) {
774 __ bind(label);
775 __ Move(this->name(), name);
776 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000777}
778
779
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000780// Generate code to check that a global property cell is empty. Create
781// the property cell at compilation time if no cell exists for the
782// property.
783static void GenerateCheckPropertyCell(MacroAssembler* masm,
784 Handle<GlobalObject> global,
785 Handle<Name> name,
786 Register scratch,
787 Label* miss) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000788 Handle<PropertyCell> cell =
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000789 GlobalObject::EnsurePropertyCell(global, name);
790 ASSERT(cell->value()->IsTheHole());
791 __ Move(scratch, cell);
danno@chromium.org41728482013-06-12 22:31:22 +0000792 __ Cmp(FieldOperand(scratch, Cell::kValueOffset),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000793 masm->isolate()->factory()->the_hole_value());
794 __ j(not_equal, miss);
795}
796
797
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000798void StoreStubCompiler::GenerateNegativeHolderLookup(
danno@chromium.orgbee51992013-07-10 14:57:15 +0000799 MacroAssembler* masm,
800 Handle<JSObject> holder,
801 Register holder_reg,
802 Handle<Name> name,
803 Label* miss) {
804 if (holder->IsJSGlobalObject()) {
805 GenerateCheckPropertyCell(
806 masm, Handle<GlobalObject>::cast(holder), name, scratch1(), miss);
807 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
808 GenerateDictionaryNegativeLookup(
809 masm, miss, holder_reg, name, scratch1(), scratch2());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000810 }
danno@chromium.orgbee51992013-07-10 14:57:15 +0000811}
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000812
danno@chromium.orgbee51992013-07-10 14:57:15 +0000813
814// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
815// store is successful.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000816void StoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
817 Handle<JSObject> object,
818 LookupResult* lookup,
819 Handle<Map> transition,
820 Handle<Name> name,
821 Register receiver_reg,
822 Register storage_reg,
823 Register value_reg,
824 Register scratch1,
825 Register scratch2,
826 Register unused,
827 Label* miss_label,
828 Label* slow) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000829 int descriptor = transition->LastAdded();
830 DescriptorArray* descriptors = transition->instance_descriptors();
831 PropertyDetails details = descriptors->GetDetails(descriptor);
832 Representation representation = details.representation();
833 ASSERT(!representation.IsNone());
834
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000835 if (details.type() == CONSTANT) {
836 Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate());
837 __ CmpObject(value_reg, constant);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000838 __ j(not_equal, miss_label);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000839 } else if (FLAG_track_fields && representation.IsSmi()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000840 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000841 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000842 __ JumpIfSmi(value_reg, miss_label);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000843 } else if (FLAG_track_double_fields && representation.IsDouble()) {
844 Label do_store, heap_number;
845 __ AllocateHeapNumber(storage_reg, scratch1, slow);
846
847 __ JumpIfNotSmi(value_reg, &heap_number);
848 __ SmiToInteger32(scratch1, value_reg);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000849 __ Cvtlsi2sd(xmm0, scratch1);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000850 __ jmp(&do_store);
851
852 __ bind(&heap_number);
853 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
danno@chromium.orgbee51992013-07-10 14:57:15 +0000854 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000855 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
856
857 __ bind(&do_store);
858 __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0);
859 }
860
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000861 // Stub never generated for non-global objects that require access
862 // checks.
863 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
864
865 // Perform map transition for the receiver if necessary.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000866 if (details.type() == FIELD &&
867 object->map()->unused_property_fields() == 0) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000868 // The properties must be extended before we can store the value.
869 // We jump to a runtime call that extends the properties array.
danno@chromium.org59400602013-08-13 17:09:37 +0000870 __ PopReturnAddressTo(scratch1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000871 __ push(receiver_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000872 __ Push(transition);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000873 __ push(value_reg);
danno@chromium.org59400602013-08-13 17:09:37 +0000874 __ PushReturnAddressFrom(scratch1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000875 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000876 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
877 masm->isolate()),
878 3,
879 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000880 return;
881 }
882
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000883 // Update the map of the object.
884 __ Move(scratch1, transition);
885 __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000886
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000887 // Update the write barrier for the map field.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000888 __ RecordWriteField(receiver_reg,
889 HeapObject::kMapOffset,
890 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000891 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000892 kDontSaveFPRegs,
893 OMIT_REMEMBERED_SET,
894 OMIT_SMI_CHECK);
895
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000896 if (details.type() == CONSTANT) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000897 ASSERT(value_reg.is(rax));
898 __ ret(0);
899 return;
900 }
901
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000902 int index = transition->instance_descriptors()->GetFieldIndex(
903 transition->LastAdded());
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000904
905 // Adjust for the number of properties stored in the object. Even in the
906 // face of a transition we can use the old map here because the size of the
907 // object and the number of in-object properties is not going to change.
908 index -= object->map()->inobject_properties();
909
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000910 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000911 SmiCheck smi_check = representation.IsTagged()
912 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000913 if (index < 0) {
914 // Set the property straight into the object.
915 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000916 if (FLAG_track_double_fields && representation.IsDouble()) {
917 __ movq(FieldOperand(receiver_reg, offset), storage_reg);
918 } else {
919 __ movq(FieldOperand(receiver_reg, offset), value_reg);
920 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000921
danno@chromium.orgf005df62013-04-30 16:36:45 +0000922 if (!FLAG_track_fields || !representation.IsSmi()) {
923 // Update the write barrier for the array address.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000924 if (!FLAG_track_double_fields || !representation.IsDouble()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000925 __ movq(storage_reg, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000926 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000927 __ RecordWriteField(
danno@chromium.orgbee51992013-07-10 14:57:15 +0000928 receiver_reg, offset, storage_reg, scratch1, kDontSaveFPRegs,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000929 EMIT_REMEMBERED_SET, smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000930 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000931 } else {
932 // Write to the properties array.
933 int offset = index * kPointerSize + FixedArray::kHeaderSize;
934 // Get the properties array (optimistically).
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000935 __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000936 if (FLAG_track_double_fields && representation.IsDouble()) {
937 __ movq(FieldOperand(scratch1, offset), storage_reg);
938 } else {
939 __ movq(FieldOperand(scratch1, offset), value_reg);
940 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000941
danno@chromium.orgf005df62013-04-30 16:36:45 +0000942 if (!FLAG_track_fields || !representation.IsSmi()) {
943 // Update the write barrier for the array address.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000944 if (!FLAG_track_double_fields || !representation.IsDouble()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000945 __ movq(storage_reg, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000946 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000947 __ RecordWriteField(
danno@chromium.orgbee51992013-07-10 14:57:15 +0000948 scratch1, offset, storage_reg, receiver_reg, kDontSaveFPRegs,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000949 EMIT_REMEMBERED_SET, smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000950 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000951 }
952
953 // Return the value (register rax).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000954 ASSERT(value_reg.is(rax));
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000955 __ ret(0);
956}
957
958
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000959// Both name_reg and receiver_reg are preserved on jumps to miss_label,
960// but may be destroyed if store is successful.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000961void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
962 Handle<JSObject> object,
963 LookupResult* lookup,
964 Register receiver_reg,
965 Register name_reg,
966 Register value_reg,
967 Register scratch1,
968 Register scratch2,
969 Label* miss_label) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000970 // Stub never generated for non-global objects that require access
971 // checks.
972 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
973
974 int index = lookup->GetFieldIndex().field_index();
975
976 // Adjust for the number of properties stored in the object. Even in the
977 // face of a transition we can use the old map here because the size of the
978 // object and the number of in-object properties is not going to change.
979 index -= object->map()->inobject_properties();
980
danno@chromium.orgf005df62013-04-30 16:36:45 +0000981 Representation representation = lookup->representation();
982 ASSERT(!representation.IsNone());
983 if (FLAG_track_fields && representation.IsSmi()) {
984 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000985 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
986 __ JumpIfSmi(value_reg, miss_label);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000987 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000988 // Load the double storage.
989 if (index < 0) {
990 int offset = object->map()->instance_size() + (index * kPointerSize);
991 __ movq(scratch1, FieldOperand(receiver_reg, offset));
992 } else {
993 __ movq(scratch1,
994 FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
995 int offset = index * kPointerSize + FixedArray::kHeaderSize;
996 __ movq(scratch1, FieldOperand(scratch1, offset));
997 }
998
999 // Store the value into the storage.
1000 Label do_store, heap_number;
1001 __ JumpIfNotSmi(value_reg, &heap_number);
1002 __ SmiToInteger32(scratch2, value_reg);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001003 __ Cvtlsi2sd(xmm0, scratch2);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001004 __ jmp(&do_store);
1005
1006 __ bind(&heap_number);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001007 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001008 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001009 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
danno@chromium.orgf005df62013-04-30 16:36:45 +00001010 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001011 __ movsd(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0);
1012 // Return the value (register rax).
1013 ASSERT(value_reg.is(rax));
1014 __ ret(0);
1015 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00001016 }
1017
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001018 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001019 SmiCheck smi_check = representation.IsTagged()
1020 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001021 if (index < 0) {
1022 // Set the property straight into the object.
1023 int offset = object->map()->instance_size() + (index * kPointerSize);
1024 __ movq(FieldOperand(receiver_reg, offset), value_reg);
1025
danno@chromium.orgf005df62013-04-30 16:36:45 +00001026 if (!FLAG_track_fields || !representation.IsSmi()) {
1027 // Update the write barrier for the array address.
1028 // Pass the value being stored in the now unused name_reg.
1029 __ movq(name_reg, value_reg);
1030 __ RecordWriteField(
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001031 receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs,
1032 EMIT_REMEMBERED_SET, smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001033 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001034 } else {
1035 // Write to the properties array.
1036 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1037 // Get the properties array (optimistically).
1038 __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
1039 __ movq(FieldOperand(scratch1, offset), value_reg);
1040
danno@chromium.orgf005df62013-04-30 16:36:45 +00001041 if (!FLAG_track_fields || !representation.IsSmi()) {
1042 // Update the write barrier for the array address.
1043 // Pass the value being stored in the now unused name_reg.
1044 __ movq(name_reg, value_reg);
1045 __ RecordWriteField(
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001046 scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs,
1047 EMIT_REMEMBERED_SET, smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001048 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001049 }
1050
1051 // Return the value (register rax).
1052 ASSERT(value_reg.is(rax));
1053 __ ret(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001054}
1055
1056
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001057// Calls GenerateCheckPropertyCell for each global object in the prototype chain
1058// from object to (but not including) holder.
1059static void GenerateCheckPropertyCells(MacroAssembler* masm,
1060 Handle<JSObject> object,
1061 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001062 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001063 Register scratch,
1064 Label* miss) {
1065 Handle<JSObject> current = object;
1066 while (!current.is_identical_to(holder)) {
1067 if (current->IsGlobalObject()) {
1068 GenerateCheckPropertyCell(masm,
1069 Handle<GlobalObject>::cast(current),
1070 name,
1071 scratch,
1072 miss);
1073 }
1074 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1075 }
1076}
1077
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001078
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001079void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001080 __ jmp(code, RelocInfo::CODE_TARGET);
1081}
1082
1083
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001084#undef __
1085#define __ ACCESS_MASM((masm()))
1086
1087
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001088Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1089 Register object_reg,
1090 Handle<JSObject> holder,
1091 Register holder_reg,
1092 Register scratch1,
1093 Register scratch2,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001094 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001095 int save_at_depth,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001096 Label* miss,
1097 PrototypeCheckType check) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001098 // Make sure that the type feedback oracle harvests the receiver map.
1099 // TODO(svenpanne) Remove this hack when all ICs are reworked.
1100 __ Move(scratch1, Handle<Map>(object->map()));
1101
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001102 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001103 // Make sure there's no overlap between holder and object registers.
1104 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1105 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1106 && !scratch2.is(scratch1));
1107
1108 // Keep track of the current object in register reg. On the first
1109 // iteration, reg is an alias for object_reg, on later iterations,
1110 // it is an alias for holder_reg.
1111 Register reg = object_reg;
1112 int depth = 0;
1113
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001114 StackArgumentsAccessor args(rsp, kFastApiCallArguments,
1115 ARGUMENTS_DONT_CONTAIN_RECEIVER);
1116 const int kHolderIndex = kFastApiCallArguments - 1 -
1117 FunctionCallbackArguments::kHolderIndex;
1118
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001119 if (save_at_depth == depth) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001120 __ movq(args.GetArgumentOperand(kHolderIndex), object_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001121 }
1122
1123 // Check the maps in the prototype chain.
1124 // Traverse the prototype chain from the object and do map checks.
1125 Handle<JSObject> current = object;
1126 while (!current.is_identical_to(holder)) {
1127 ++depth;
1128
1129 // Only global objects and objects that do not require access
1130 // checks are allowed in stubs.
1131 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1132
1133 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1134 if (!current->HasFastProperties() &&
1135 !current->IsJSGlobalObject() &&
1136 !current->IsJSGlobalProxy()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001137 if (!name->IsUniqueName()) {
1138 ASSERT(name->IsString());
1139 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001140 }
1141 ASSERT(current->property_dictionary()->FindEntry(*name) ==
ulan@chromium.org750145a2013-03-07 15:14:13 +00001142 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001143
1144 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1145 scratch1, scratch2);
1146
1147 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1148 reg = holder_reg; // From now on the object will be in holder_reg.
1149 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1150 } else {
1151 bool in_new_space = heap()->InNewSpace(*prototype);
1152 Handle<Map> current_map(current->map());
1153 if (in_new_space) {
1154 // Save the map in scratch1 for later.
1155 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001156 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001157 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001158 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001159 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001160
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001161 // Check access rights to the global object. This has to happen after
1162 // the map check so that we know that the object is actually a global
1163 // object.
1164 if (current->IsJSGlobalProxy()) {
1165 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1166 }
1167 reg = holder_reg; // From now on the object will be in holder_reg.
1168
1169 if (in_new_space) {
1170 // The prototype is in new space; we cannot store a reference to it
1171 // in the code. Load it from the map.
1172 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1173 } else {
1174 // The prototype is in old space; load it directly.
1175 __ Move(reg, prototype);
1176 }
1177 }
1178
1179 if (save_at_depth == depth) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001180 __ movq(args.GetArgumentOperand(kHolderIndex), reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001181 }
1182
1183 // Go to the next object in the prototype chain.
1184 current = prototype;
1185 }
1186 ASSERT(current.is_identical_to(holder));
1187
1188 // Log the check depth.
1189 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1190
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001191 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1192 // Check the holder map.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001193 __ CheckMap(reg, Handle<Map>(holder->map()), miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001194 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001195
1196 // Perform security check for access to the global object.
1197 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1198 if (current->IsJSGlobalProxy()) {
1199 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1200 }
1201
1202 // If we've skipped any global objects, it's not enough to verify that
1203 // their maps haven't changed. We also need to check that the property
1204 // cell for the property is still empty.
1205 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1206
1207 // Return the register containing the holder.
1208 return reg;
1209}
1210
1211
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001212void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name,
1213 Label* success,
1214 Label* miss) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001215 if (!miss->is_unused()) {
1216 __ jmp(success);
1217 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001218 TailCallBuiltin(masm(), MissBuiltin(kind()));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001219 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001220}
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001221
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001222
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001223void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name,
1224 Label* success,
1225 Label* miss) {
danno@chromium.orgbee51992013-07-10 14:57:15 +00001226 if (!miss->is_unused()) {
1227 __ jmp(success);
1228 GenerateRestoreName(masm(), miss, name);
1229 TailCallBuiltin(masm(), MissBuiltin(kind()));
1230 }
1231}
1232
1233
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001234Register LoadStubCompiler::CallbackHandlerFrontend(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001235 Handle<JSObject> object,
1236 Register object_reg,
1237 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001238 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001239 Label* success,
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001240 Handle<Object> callback) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001241 Label miss;
1242
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001243 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001244
1245 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1246 ASSERT(!reg.is(scratch2()));
1247 ASSERT(!reg.is(scratch3()));
1248 ASSERT(!reg.is(scratch4()));
1249
1250 // Load the properties dictionary.
1251 Register dictionary = scratch4();
1252 __ movq(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset));
1253
1254 // Probe the dictionary.
1255 Label probe_done;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001256 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1257 &miss,
1258 &probe_done,
1259 dictionary,
1260 this->name(),
1261 scratch2(),
1262 scratch3());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001263 __ bind(&probe_done);
1264
1265 // If probing finds an entry in the dictionary, scratch3 contains the
1266 // index into the dictionary. Check that the value is the callback.
1267 Register index = scratch3();
1268 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +00001269 NameDictionary::kHeaderSize +
1270 NameDictionary::kElementsStartIndex * kPointerSize;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001271 const int kValueOffset = kElementsStartOffset + kPointerSize;
1272 __ movq(scratch2(),
1273 Operand(dictionary, index, times_pointer_size,
1274 kValueOffset - kHeapObjectTag));
1275 __ movq(scratch3(), callback, RelocInfo::EMBEDDED_OBJECT);
1276 __ cmpq(scratch2(), scratch3());
1277 __ j(not_equal, &miss);
1278 }
1279
danno@chromium.orgbee51992013-07-10 14:57:15 +00001280 HandlerFrontendFooter(name, success, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001281 return reg;
1282}
1283
1284
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001285void LoadStubCompiler::NonexistentHandlerFrontend(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001286 Handle<JSObject> object,
1287 Handle<JSObject> last,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001288 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001289 Label* success,
1290 Handle<GlobalObject> global) {
1291 Label miss;
1292
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001293 HandlerFrontendHeader(object, receiver(), last, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001294
1295 // If the last object in the prototype chain is a global object,
1296 // check that the global property cell is empty.
1297 if (!global.is_null()) {
1298 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1299 }
1300
danno@chromium.orgbee51992013-07-10 14:57:15 +00001301 HandlerFrontendFooter(name, success, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001302}
1303
1304
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001305void LoadStubCompiler::GenerateLoadField(Register reg,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001306 Handle<JSObject> holder,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001307 PropertyIndex field,
1308 Representation representation) {
1309 if (!reg.is(receiver())) __ movq(receiver(), reg);
1310 if (kind() == Code::LOAD_IC) {
1311 LoadFieldStub stub(field.is_inobject(holder),
1312 field.translate(holder),
1313 representation);
1314 GenerateTailCall(masm(), stub.GetCode(isolate()));
1315 } else {
1316 KeyedLoadFieldStub stub(field.is_inobject(holder),
1317 field.translate(holder),
1318 representation);
1319 GenerateTailCall(masm(), stub.GetCode(isolate()));
1320 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001321}
1322
1323
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001324void LoadStubCompiler::GenerateLoadCallback(
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001325 const CallOptimization& call_optimization) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001326 GenerateFastApiCall(
1327 masm(), call_optimization, receiver(), scratch3(), 0, NULL);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001328}
1329
1330
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001331void LoadStubCompiler::GenerateLoadCallback(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001332 Register reg,
1333 Handle<ExecutableAccessorInfo> callback) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001334 // Insert additional parameters into the stack frame above return address.
danno@chromium.orgc9db9202013-06-20 13:09:46 +00001335 ASSERT(!scratch4().is(reg));
danno@chromium.org59400602013-08-13 17:09:37 +00001336 __ PopReturnAddressTo(scratch4());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001337
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001338 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
1339 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
1340 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
1341 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
1342 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
1343 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
1344 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001345 __ push(receiver()); // receiver
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001346 if (heap()->InNewSpace(callback->data())) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001347 ASSERT(!scratch2().is(reg));
1348 __ Move(scratch2(), callback);
1349 __ push(FieldOperand(scratch2(),
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001350 ExecutableAccessorInfo::kDataOffset)); // data
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001351 } else {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001352 __ Push(Handle<Object>(callback->data(), isolate()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001353 }
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001354 ASSERT(!kScratchRegister.is(reg));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001355 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
1356 __ push(kScratchRegister); // return value
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001357 __ push(kScratchRegister); // return value default
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001358 __ PushAddress(ExternalReference::isolate_address(isolate()));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001359 __ push(reg); // holder
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001360 __ push(name()); // name
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001361 // Save a pointer to where we pushed the arguments pointer. This will be
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001362 // passed as the const PropertyAccessorInfo& to the C++ callback.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001363
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001364 Address getter_address = v8::ToCData<Address>(callback->getter());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001365
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001366#if defined(__MINGW64__) || defined(_WIN64)
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001367 Register getter_arg = r8;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001368 Register accessor_info_arg = rdx;
1369 Register name_arg = rcx;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001370#else
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001371 Register getter_arg = rdx;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001372 Register accessor_info_arg = rsi;
1373 Register name_arg = rdi;
1374#endif
1375
danno@chromium.orgc9db9202013-06-20 13:09:46 +00001376 ASSERT(!name_arg.is(scratch4()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001377 __ movq(name_arg, rsp);
danno@chromium.org59400602013-08-13 17:09:37 +00001378 __ PushReturnAddressFrom(scratch4());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001379
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001380 // v8::Arguments::values_ and handler for name.
1381 const int kStackSpace = PropertyCallbackArguments::kArgsLength + 1;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001382
1383 // Allocate v8::AccessorInfo in non-GCed stack space.
1384 const int kArgStackSpace = 1;
1385
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001386 __ PrepareCallApiFunction(kArgStackSpace);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001387 __ lea(rax, Operand(name_arg, 1 * kPointerSize));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001388
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001389 // v8::PropertyAccessorInfo::args_.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001390 __ movq(StackSpaceOperand(0), rax);
1391
1392 // The context register (rsi) has been saved in PrepareCallApiFunction and
1393 // could be used to pass arguments.
1394 __ lea(accessor_info_arg, StackSpaceOperand(0));
1395
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001396 Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001397
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001398 // The name handler is counted as an argument.
1399 StackArgumentsAccessor args(rbp, PropertyCallbackArguments::kArgsLength);
1400 Operand return_value_operand = args.GetArgumentOperand(
1401 PropertyCallbackArguments::kArgsLength - 1 -
1402 PropertyCallbackArguments::kReturnValueOffset);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001403 __ CallApiFunctionAndReturn(getter_address,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001404 thunk_address,
1405 getter_arg,
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001406 kStackSpace,
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001407 return_value_operand,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001408 NULL);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001409}
1410
1411
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001412void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001413 // Return the constant value.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001414 __ LoadObject(rax, value);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001415 __ ret(0);
1416}
1417
1418
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001419void LoadStubCompiler::GenerateLoadInterceptor(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001420 Register holder_reg,
1421 Handle<JSObject> object,
1422 Handle<JSObject> interceptor_holder,
1423 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001424 Handle<Name> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001425 ASSERT(interceptor_holder->HasNamedInterceptor());
1426 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1427
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001428 // So far the most popular follow ups for interceptor loads are FIELD
1429 // and CALLBACKS, so inline only them, other cases may be added
1430 // later.
1431 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001432 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001433 if (lookup->IsField()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001434 compile_followup_inline = true;
1435 } else if (lookup->type() == CALLBACKS &&
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001436 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1437 ExecutableAccessorInfo* callback =
1438 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001439 compile_followup_inline = callback->getter() != NULL &&
1440 callback->IsCompatibleReceiver(*object);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001441 }
1442 }
1443
1444 if (compile_followup_inline) {
1445 // Compile the interceptor call, followed by inline code to load the
1446 // property from further up the prototype chain if the call fails.
1447 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001448 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001449
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001450 // Preserve the receiver register explicitly whenever it is different from
1451 // the holder and it is needed should the interceptor return without any
1452 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1453 // the FIELD case might cause a miss during the prototype check.
1454 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001455 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001456 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1457
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001458 // Save necessary data before invoking an interceptor.
1459 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001460 {
1461 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001462
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001463 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001464 __ push(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001465 }
1466 __ push(holder_reg);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001467 __ push(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001468
1469 // Invoke an interceptor. Note: map checks from receiver to
1470 // interceptor's holder has been compiled before (see a caller
1471 // of this method.)
1472 CompileCallLoadPropertyWithInterceptor(masm(),
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001473 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001474 holder_reg,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001475 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001476 interceptor_holder);
1477
1478 // Check if interceptor provided a value for property. If it's
1479 // the case, return immediately.
1480 Label interceptor_failed;
1481 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
1482 __ j(equal, &interceptor_failed);
1483 frame_scope.GenerateLeaveFrame();
1484 __ ret(0);
1485
1486 __ bind(&interceptor_failed);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001487 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001488 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001489 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001490 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001491 }
1492
1493 // Leave the internal frame.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001494 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001495
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001496 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001497 } else { // !compile_followup_inline
1498 // Call the runtime system to load the interceptor.
1499 // Check that the maps haven't changed.
danno@chromium.org59400602013-08-13 17:09:37 +00001500 __ PopReturnAddressTo(scratch2());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001501 PushInterceptorArguments(masm(), receiver(), holder_reg,
1502 this->name(), interceptor_holder);
danno@chromium.org59400602013-08-13 17:09:37 +00001503 __ PushReturnAddressFrom(scratch2());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001504
1505 ExternalReference ref = ExternalReference(
lrn@chromium.org7516f052011-03-30 08:52:27 +00001506 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001507 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001508 }
1509}
1510
1511
ulan@chromium.org750145a2013-03-07 15:14:13 +00001512void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001513 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001514 __ Cmp(rcx, name);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001515 __ j(not_equal, miss);
1516 }
1517}
1518
1519
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001520void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1521 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001522 Handle<Name> name,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001523 Label* miss) {
1524 ASSERT(holder->IsGlobalObject());
1525
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001526 StackArgumentsAccessor args(rsp, arguments());
1527 __ movq(rdx, args.GetReceiverOperand());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001528
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001529
1530 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001531 __ JumpIfSmi(rdx, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001532 CheckPrototypes(object, rdx, holder, rbx, rax, rdi, name, miss);
1533}
1534
1535
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001536void CallStubCompiler::GenerateLoadFunctionFromCell(
danno@chromium.org41728482013-06-12 22:31:22 +00001537 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001538 Handle<JSFunction> function,
1539 Label* miss) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001540 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001541 __ Move(rdi, cell);
danno@chromium.org41728482013-06-12 22:31:22 +00001542 __ movq(rdi, FieldOperand(rdi, Cell::kValueOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001543
1544 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001545 if (heap()->InNewSpace(*function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001546 // We can't embed a pointer to a function in new space so we have
1547 // to verify that the shared function info is unchanged. This has
1548 // the nice side effect that multiple closures based on the same
1549 // function can all use this call IC. Before we load through the
1550 // function, we have to verify that it still is a function.
1551 __ JumpIfSmi(rdi, miss);
1552 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax);
1553 __ j(not_equal, miss);
1554
1555 // Check the shared function info. Make sure it hasn't changed.
1556 __ Move(rax, Handle<SharedFunctionInfo>(function->shared()));
1557 __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001558 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001559 __ Cmp(rdi, function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001560 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001561 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001562}
1563
1564
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001565void CallStubCompiler::GenerateMissBranch() {
1566 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001567 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1568 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001569 extra_state_);
1570 __ Jump(code, RelocInfo::CODE_TARGET);
1571}
1572
1573
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001574Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1575 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001576 PropertyIndex index,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001577 Handle<Name> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001578 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001579 // rcx : function name
1580 // rsp[0] : return address
1581 // rsp[8] : argument argc
1582 // rsp[16] : argument argc - 1
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001583 // ...
ager@chromium.org5c838252010-02-19 08:53:10 +00001584 // rsp[argc * 8] : argument 1
1585 // rsp[(argc + 1) * 8] : argument 0 = receiver
1586 // -----------------------------------
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001587 Label miss;
1588
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001589 GenerateNameCheck(name, &miss);
1590
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001591 StackArgumentsAccessor args(rsp, arguments());
1592 __ movq(rdx, args.GetReceiverOperand());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001593
1594 // Check that the receiver isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001595 __ JumpIfSmi(rdx, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001596
1597 // Do the right check and compute the holder register.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001598 Register reg = CheckPrototypes(object, rdx, holder, rbx, rax, rdi,
1599 name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001600
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001601 GenerateFastPropertyLoad(masm(), rdi, reg, index.is_inobject(holder),
1602 index.translate(holder), Representation::Tagged());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001603
1604 // Check that the function really is a function.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001605 __ JumpIfSmi(rdi, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001606 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rbx);
1607 __ j(not_equal, &miss);
1608
1609 // Patch the receiver on the stack with the global proxy if
1610 // necessary.
1611 if (object->IsGlobalObject()) {
1612 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001613 __ movq(args.GetReceiverOperand(), rdx);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001614 }
1615
1616 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001617 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001618 ? CALL_AS_FUNCTION
1619 : CALL_AS_METHOD;
1620 __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
1621 NullCallWrapper(), call_kind);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001622
1623 // Handle call cache miss.
1624 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001625 GenerateMissBranch();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001626
1627 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001628 return GetCode(Code::FIELD, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001629}
1630
1631
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001632Handle<Code> CallStubCompiler::CompileArrayCodeCall(
1633 Handle<Object> object,
1634 Handle<JSObject> holder,
1635 Handle<Cell> cell,
1636 Handle<JSFunction> function,
1637 Handle<String> name,
1638 Code::StubType type) {
1639 Label miss;
1640
1641 // Check that function is still array
1642 const int argc = arguments().immediate();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001643 StackArgumentsAccessor args(rsp, argc);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001644 GenerateNameCheck(name, &miss);
1645
1646 if (cell.is_null()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001647 __ movq(rdx, args.GetReceiverOperand());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001648
1649 // Check that the receiver isn't a smi.
1650 __ JumpIfSmi(rdx, &miss);
1651 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
1652 name, &miss);
1653 } else {
1654 ASSERT(cell->value() == *function);
1655 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1656 &miss);
1657 GenerateLoadFunctionFromCell(cell, function, &miss);
1658 }
1659
danno@chromium.orgbee51992013-07-10 14:57:15 +00001660 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite();
1661 site->set_transition_info(Smi::FromInt(GetInitialFastElementsKind()));
1662 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001663 __ movq(rax, Immediate(argc));
danno@chromium.orgbee51992013-07-10 14:57:15 +00001664 __ Move(rbx, site_feedback_cell);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001665 __ Move(rdi, function);
1666
1667 ArrayConstructorStub stub(isolate());
1668 __ TailCallStub(&stub);
1669
1670 __ bind(&miss);
1671 GenerateMissBranch();
1672
1673 // Return the generated code.
1674 return GetCode(type, name);
1675}
1676
1677
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001678Handle<Code> CallStubCompiler::CompileArrayPushCall(
1679 Handle<Object> object,
1680 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00001681 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001682 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001683 Handle<String> name,
1684 Code::StubType type) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001685 // ----------- S t a t e -------------
1686 // -- rcx : name
1687 // -- rsp[0] : return address
1688 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1689 // -- ...
1690 // -- rsp[(argc + 1) * 8] : receiver
1691 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +00001692
1693 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001694 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001695
1696 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001697 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001698
ager@chromium.orgac091b72010-05-05 07:34:42 +00001699 const int argc = arguments().immediate();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001700 StackArgumentsAccessor args(rsp, argc);
1701 __ movq(rdx, args.GetReceiverOperand());
ager@chromium.orgac091b72010-05-05 07:34:42 +00001702
1703 // Check that the receiver isn't a smi.
1704 __ JumpIfSmi(rdx, &miss);
1705
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001706 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
1707 name, &miss);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001708
1709 if (argc == 0) {
1710 // Noop, return the length.
1711 __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset));
1712 __ ret((argc + 1) * kPointerSize);
1713 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001714 Label call_builtin;
1715
ager@chromium.orgac091b72010-05-05 07:34:42 +00001716 if (argc == 1) { // Otherwise fall through to call builtin.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001717 Label attempt_to_grow_elements, with_write_barrier, check_double;
ager@chromium.orgac091b72010-05-05 07:34:42 +00001718
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001719 // Get the elements array of the object.
1720 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
1721
1722 // Check that the elements are in fast mode and writable.
1723 __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
1724 factory()->fixed_array_map());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001725 __ j(not_equal, &check_double);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001726
ager@chromium.orgac091b72010-05-05 07:34:42 +00001727 // Get the array's length into rax and calculate new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001728 __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001729 STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001730 __ addl(rax, Immediate(argc));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001731
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001732 // Get the elements' length into rcx.
1733 __ SmiToInteger32(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001734
1735 // Check if we could survive without allocation.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001736 __ cmpl(rax, rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001737 __ j(greater, &attempt_to_grow_elements);
1738
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001739 // Check if value is a smi.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001740 __ movq(rcx, args.GetArgumentOperand(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001741 __ JumpIfNotSmi(rcx, &with_write_barrier);
1742
ager@chromium.orgac091b72010-05-05 07:34:42 +00001743 // Save new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001744 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001745
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001746 // Store the value.
1747 __ movq(FieldOperand(rdi,
1748 rax,
1749 times_pointer_size,
1750 FixedArray::kHeaderSize - argc * kPointerSize),
1751 rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001752
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001753 __ Integer32ToSmi(rax, rax); // Return new length as smi.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001754 __ ret((argc + 1) * kPointerSize);
1755
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001756 __ bind(&check_double);
1757
1758 // Check that the elements are in double mode.
1759 __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
1760 factory()->fixed_double_array_map());
1761 __ j(not_equal, &call_builtin);
1762
1763 // Get the array's length into rax and calculate new length.
1764 __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset));
1765 STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue);
1766 __ addl(rax, Immediate(argc));
1767
1768 // Get the elements' length into rcx.
1769 __ SmiToInteger32(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
1770
1771 // Check if we could survive without allocation.
1772 __ cmpl(rax, rcx);
1773 __ j(greater, &call_builtin);
1774
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001775 __ movq(rcx, args.GetArgumentOperand(1));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001776 __ StoreNumberToDoubleElements(
1777 rcx, rdi, rax, xmm0, &call_builtin, argc * kDoubleSize);
1778
1779 // Save new length.
1780 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
1781 __ Integer32ToSmi(rax, rax); // Return new length as smi.
1782 __ ret((argc + 1) * kPointerSize);
1783
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001784 __ bind(&with_write_barrier);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001785
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001786 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
1787
1788 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1789 Label fast_object, not_fast_object;
1790 __ CheckFastObjectElements(rbx, &not_fast_object, Label::kNear);
1791 __ jmp(&fast_object);
1792 // In case of fast smi-only, convert to fast object, otherwise bail out.
1793 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001794 __ CheckFastSmiElements(rbx, &call_builtin);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001795 __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset),
1796 factory()->heap_number_map());
1797 __ j(equal, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001798 // rdx: receiver
1799 // rbx: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001800
1801 Label try_holey_map;
1802 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001803 FAST_ELEMENTS,
1804 rbx,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001805 rdi,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001806 &try_holey_map);
1807
1808 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001809 GenerateMapChangeElementsTransition(masm(),
1810 DONT_TRACK_ALLOCATION_SITE,
1811 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001812 // Restore edi.
1813 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
1814 __ jmp(&fast_object);
1815
1816 __ bind(&try_holey_map);
1817 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1818 FAST_HOLEY_ELEMENTS,
1819 rbx,
1820 rdi,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001821 &call_builtin);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001822 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001823 GenerateMapChangeElementsTransition(masm(),
1824 DONT_TRACK_ALLOCATION_SITE,
1825 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001826 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001827 __ bind(&fast_object);
1828 } else {
1829 __ CheckFastObjectElements(rbx, &call_builtin);
1830 }
1831
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001832 // Save new length.
1833 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001834
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001835 // Store the value.
1836 __ lea(rdx, FieldOperand(rdi,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001837 rax, times_pointer_size,
1838 FixedArray::kHeaderSize - argc * kPointerSize));
1839 __ movq(Operand(rdx, 0), rcx);
1840
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001841 __ RecordWrite(rdi, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001842 OMIT_SMI_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001843
1844 __ Integer32ToSmi(rax, rax); // Return new length as smi.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001845 __ ret((argc + 1) * kPointerSize);
1846
1847 __ bind(&attempt_to_grow_elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001848 if (!FLAG_inline_new) {
1849 __ jmp(&call_builtin);
1850 }
1851
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001852 __ movq(rbx, args.GetArgumentOperand(1));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001853 // Growing elements that are SMI-only requires special handling in case
1854 // the new element is non-Smi. For now, delegate to the builtin.
1855 Label no_fast_elements_check;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001856 __ JumpIfSmi(rbx, &no_fast_elements_check);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001857 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
1858 __ CheckFastObjectElements(rcx, &call_builtin, Label::kFar);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001859 __ bind(&no_fast_elements_check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001860
ager@chromium.orgac091b72010-05-05 07:34:42 +00001861 ExternalReference new_space_allocation_top =
lrn@chromium.org7516f052011-03-30 08:52:27 +00001862 ExternalReference::new_space_allocation_top_address(isolate());
ager@chromium.orgac091b72010-05-05 07:34:42 +00001863 ExternalReference new_space_allocation_limit =
lrn@chromium.org7516f052011-03-30 08:52:27 +00001864 ExternalReference::new_space_allocation_limit_address(isolate());
ager@chromium.orgac091b72010-05-05 07:34:42 +00001865
1866 const int kAllocationDelta = 4;
1867 // Load top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001868 __ Load(rcx, new_space_allocation_top);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001869
1870 // Check if it's the end of elements.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001871 __ lea(rdx, FieldOperand(rdi,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001872 rax, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001873 FixedArray::kHeaderSize - argc * kPointerSize));
1874 __ cmpq(rdx, rcx);
1875 __ j(not_equal, &call_builtin);
1876 __ addq(rcx, Immediate(kAllocationDelta * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001877 Operand limit_operand =
1878 masm()->ExternalOperand(new_space_allocation_limit);
1879 __ cmpq(rcx, limit_operand);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001880 __ j(above, &call_builtin);
1881
1882 // We fit and could grow elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001883 __ Store(new_space_allocation_top, rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001884
1885 // Push the argument...
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001886 __ movq(Operand(rdx, 0), rbx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001887 // ... and fill the rest with holes.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001888 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001889 for (int i = 1; i < kAllocationDelta; i++) {
1890 __ movq(Operand(rdx, i * kPointerSize), kScratchRegister);
1891 }
1892
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001893 // We know the elements array is in new space so we don't need the
1894 // remembered set, but we just pushed a value onto it so we may have to
1895 // tell the incremental marker to rescan the object that we just grew. We
1896 // don't need to worry about the holes because they are in old space and
1897 // already marked black.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001898 __ RecordWrite(rdi, rdx, rbx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001899
ager@chromium.orgac091b72010-05-05 07:34:42 +00001900 // Restore receiver to rdx as finish sequence assumes it's here.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001901 __ movq(rdx, args.GetReceiverOperand());
ager@chromium.orgac091b72010-05-05 07:34:42 +00001902
1903 // Increment element's and array's sizes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001904 __ SmiAddConstant(FieldOperand(rdi, FixedArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001905 Smi::FromInt(kAllocationDelta));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001906
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001907 // Make new length a smi before returning it.
1908 __ Integer32ToSmi(rax, rax);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001909 __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001910
ager@chromium.orgac091b72010-05-05 07:34:42 +00001911 __ ret((argc + 1) * kPointerSize);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001912 }
1913
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001914 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001915 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001916 isolate()),
ager@chromium.orgac091b72010-05-05 07:34:42 +00001917 argc + 1,
1918 1);
1919 }
1920
1921 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001922 GenerateMissBranch();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001923
1924 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001925 return GetCode(type, name);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001926}
1927
1928
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001929Handle<Code> CallStubCompiler::CompileArrayPopCall(
1930 Handle<Object> object,
1931 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00001932 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001933 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001934 Handle<String> name,
1935 Code::StubType type) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001936 // ----------- S t a t e -------------
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001937 // -- rcx : name
1938 // -- rsp[0] : return address
1939 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
ager@chromium.orgac091b72010-05-05 07:34:42 +00001940 // -- ...
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001941 // -- rsp[(argc + 1) * 8] : receiver
ager@chromium.orgac091b72010-05-05 07:34:42 +00001942 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +00001943
1944 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001945 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001946
1947 Label miss, return_undefined, call_builtin;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001948 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001949
ager@chromium.orgac091b72010-05-05 07:34:42 +00001950 const int argc = arguments().immediate();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001951 StackArgumentsAccessor args(rsp, argc);
1952 __ movq(rdx, args.GetReceiverOperand());
ager@chromium.orgac091b72010-05-05 07:34:42 +00001953
1954 // Check that the receiver isn't a smi.
1955 __ JumpIfSmi(rdx, &miss);
1956
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001957 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
1958 name, &miss);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001959
1960 // Get the elements array of the object.
1961 __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
1962
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001963 // Check that the elements are in fast mode and writable.
1964 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
1965 Heap::kFixedArrayMapRootIndex);
1966 __ j(not_equal, &call_builtin);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001967
1968 // Get the array's length into rcx and calculate new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001969 __ SmiToInteger32(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
1970 __ subl(rcx, Immediate(1));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001971 __ j(negative, &return_undefined);
1972
1973 // Get the last element.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001974 __ LoadRoot(r9, Heap::kTheHoleValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001975 __ movq(rax, FieldOperand(rbx,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001976 rcx, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001977 FixedArray::kHeaderSize));
1978 // Check if element is already the hole.
1979 __ cmpq(rax, r9);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001980 // If so, call slow-case to also check prototypes for value.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001981 __ j(equal, &call_builtin);
1982
1983 // Set the array's length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001984 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001985
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001986 // Fill with the hole and return original value.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001987 __ movq(FieldOperand(rbx,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001988 rcx, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001989 FixedArray::kHeaderSize),
1990 r9);
1991 __ ret((argc + 1) * kPointerSize);
1992
1993 __ bind(&return_undefined);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001994 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001995 __ ret((argc + 1) * kPointerSize);
1996
1997 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001998 __ TailCallExternalReference(
lrn@chromium.org7516f052011-03-30 08:52:27 +00001999 ExternalReference(Builtins::c_ArrayPop, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002000 argc + 1,
2001 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002002
ager@chromium.orgac091b72010-05-05 07:34:42 +00002003 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002004 GenerateMissBranch();
ager@chromium.orgac091b72010-05-05 07:34:42 +00002005
2006 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002007 return GetCode(type, name);
ager@chromium.orgac091b72010-05-05 07:34:42 +00002008}
2009
2010
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002011Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
2012 Handle<Object> object,
2013 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002014 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002015 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002016 Handle<String> name,
2017 Code::StubType type) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002018 // ----------- S t a t e -------------
2019 // -- rcx : function name
2020 // -- rsp[0] : return address
2021 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
2022 // -- ...
2023 // -- rsp[(argc + 1) * 8] : receiver
2024 // -----------------------------------
2025
2026 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002027 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002028
2029 const int argc = arguments().immediate();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002030 StackArgumentsAccessor args(rsp, argc);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002031
2032 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002033 Label name_miss;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002034 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002035 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002036 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002037 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002038 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002039 index_out_of_range_label = &miss;
2040 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002041 GenerateNameCheck(name, &name_miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002042
2043 // Check that the maps starting from the prototype haven't changed.
2044 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2045 Context::STRING_FUNCTION_INDEX,
2046 rax,
2047 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002048 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002049 CheckPrototypes(
2050 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2051 rax, holder, rbx, rdx, rdi, name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002052
2053 Register receiver = rbx;
2054 Register index = rdi;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002055 Register result = rax;
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002056 __ movq(receiver, args.GetReceiverOperand());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002057 if (argc > 0) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002058 __ movq(index, args.GetArgumentOperand(1));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002059 } else {
2060 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2061 }
2062
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002063 StringCharCodeAtGenerator generator(receiver,
2064 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002065 result,
2066 &miss, // When not a string.
2067 &miss, // When not a number.
2068 index_out_of_range_label,
2069 STRING_INDEX_IS_NUMBER);
2070 generator.GenerateFast(masm());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002071 __ ret((argc + 1) * kPointerSize);
2072
2073 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002074 generator.GenerateSlow(masm(), call_helper);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002075
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002076 if (index_out_of_range.is_linked()) {
2077 __ bind(&index_out_of_range);
2078 __ LoadRoot(rax, Heap::kNanValueRootIndex);
2079 __ ret((argc + 1) * kPointerSize);
2080 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002081
2082 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002083 // Restore function name in rcx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002084 __ Move(rcx, name);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002085 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002086 GenerateMissBranch();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002087
2088 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002089 return GetCode(type, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002090}
2091
2092
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002093Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2094 Handle<Object> object,
2095 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002096 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002097 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002098 Handle<String> name,
2099 Code::StubType type) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002100 // ----------- S t a t e -------------
2101 // -- rcx : function name
2102 // -- rsp[0] : return address
2103 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
2104 // -- ...
2105 // -- rsp[(argc + 1) * 8] : receiver
2106 // -----------------------------------
2107
2108 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002109 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002110
2111 const int argc = arguments().immediate();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002112 StackArgumentsAccessor args(rsp, argc);
2113
ricow@chromium.org65fae842010-08-25 15:26:24 +00002114 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002115 Label name_miss;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002116 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002117 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002118 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002119 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002120 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002121 index_out_of_range_label = &miss;
2122 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002123 GenerateNameCheck(name, &name_miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002124
2125 // Check that the maps starting from the prototype haven't changed.
2126 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2127 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002128 rax,
2129 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002130 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002131 CheckPrototypes(
2132 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2133 rax, holder, rbx, rdx, rdi, name, &miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002134
2135 Register receiver = rax;
2136 Register index = rdi;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002137 Register scratch = rdx;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002138 Register result = rax;
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002139 __ movq(receiver, args.GetReceiverOperand());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002140 if (argc > 0) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002141 __ movq(index, args.GetArgumentOperand(1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002142 } else {
2143 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2144 }
2145
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002146 StringCharAtGenerator generator(receiver,
2147 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002148 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002149 result,
2150 &miss, // When not a string.
2151 &miss, // When not a number.
2152 index_out_of_range_label,
2153 STRING_INDEX_IS_NUMBER);
2154 generator.GenerateFast(masm());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002155 __ ret((argc + 1) * kPointerSize);
2156
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002157 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002158 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002159
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002160 if (index_out_of_range.is_linked()) {
2161 __ bind(&index_out_of_range);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002162 __ LoadRoot(rax, Heap::kempty_stringRootIndex);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002163 __ ret((argc + 1) * kPointerSize);
2164 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002165 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002166 // Restore function name in rcx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002167 __ Move(rcx, name);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002168 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002169 GenerateMissBranch();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002170
2171 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002172 return GetCode(type, name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002173}
2174
2175
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002176Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2177 Handle<Object> object,
2178 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002179 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002180 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002181 Handle<String> name,
2182 Code::StubType type) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002183 // ----------- S t a t e -------------
2184 // -- rcx : function name
2185 // -- rsp[0] : return address
2186 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
2187 // -- ...
2188 // -- rsp[(argc + 1) * 8] : receiver
2189 // -----------------------------------
2190
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002191 // If the object is not a JSObject or we got an unexpected number of
2192 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002193 const int argc = arguments().immediate();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002194 StackArgumentsAccessor args(rsp, argc);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002195 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002196
2197 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002198 GenerateNameCheck(name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002199
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002200 if (cell.is_null()) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002201 __ movq(rdx, args.GetReceiverOperand());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002202 __ JumpIfSmi(rdx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002203 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
2204 name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002205 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002206 ASSERT(cell->value() == *function);
2207 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2208 &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002209 GenerateLoadFunctionFromCell(cell, function, &miss);
2210 }
2211
2212 // Load the char code argument.
2213 Register code = rbx;
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002214 __ movq(code, args.GetArgumentOperand(1));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002215
2216 // Check the code is a smi.
2217 Label slow;
2218 __ JumpIfNotSmi(code, &slow);
2219
2220 // Convert the smi code to uint16.
2221 __ SmiAndConstant(code, code, Smi::FromInt(0xffff));
2222
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002223 StringCharFromCodeGenerator generator(code, rax);
2224 generator.GenerateFast(masm());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002225 __ ret(2 * kPointerSize);
2226
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002227 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002228 generator.GenerateSlow(masm(), call_helper);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002229
2230 // Tail call the full function. We do not have to patch the receiver
2231 // because the function makes no use of it.
2232 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002233 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002234 ? CALL_AS_FUNCTION
2235 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002236 ParameterCount expected(function);
2237 __ InvokeFunction(function, expected, arguments(),
2238 JUMP_FUNCTION, NullCallWrapper(), call_kind);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002239
2240 __ bind(&miss);
2241 // rcx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002242 GenerateMissBranch();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002243
2244 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002245 return GetCode(type, name);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002246}
2247
2248
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002249Handle<Code> CallStubCompiler::CompileMathFloorCall(
2250 Handle<Object> object,
2251 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002252 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002253 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002254 Handle<String> name,
2255 Code::StubType type) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002256 // ----------- S t a t e -------------
2257 // -- rcx : name
2258 // -- rsp[0] : return address
2259 // -- rsp[(argc - n) * 4] : arg[n] (zero-based)
2260 // -- ...
2261 // -- rsp[(argc + 1) * 4] : receiver
2262 // -----------------------------------
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002263 const int argc = arguments().immediate();
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002264 StackArgumentsAccessor args(rsp, argc);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002265
2266 // If the object is not a JSObject or we got an unexpected number of
2267 // arguments, bail out to the regular call.
2268 if (!object->IsJSObject() || argc != 1) {
2269 return Handle<Code>::null();
2270 }
2271
2272 Label miss;
2273 GenerateNameCheck(name, &miss);
2274
2275 if (cell.is_null()) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002276 __ movq(rdx, args.GetReceiverOperand());
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002277
2278 STATIC_ASSERT(kSmiTag == 0);
2279 __ JumpIfSmi(rdx, &miss);
2280
2281 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
2282 name, &miss);
2283 } else {
2284 ASSERT(cell->value() == *function);
2285 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2286 &miss);
2287 GenerateLoadFunctionFromCell(cell, function, &miss);
2288 }
2289
2290 // Load the (only) argument into rax.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002291 __ movq(rax, args.GetArgumentOperand(1));
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002292
2293 // Check if the argument is a smi.
2294 Label smi;
2295 STATIC_ASSERT(kSmiTag == 0);
2296 __ JumpIfSmi(rax, &smi);
2297
2298 // Check if the argument is a heap number and load its value into xmm0.
2299 Label slow;
2300 __ CheckMap(rax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
2301 __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
2302
2303 // Check if the argument is strictly positive. Note this also discards NaN.
2304 __ xorpd(xmm1, xmm1);
2305 __ ucomisd(xmm0, xmm1);
2306 __ j(below_equal, &slow);
2307
2308 // Do a truncating conversion.
2309 __ cvttsd2si(rax, xmm0);
2310
2311 // Checks for 0x80000000 which signals a failed conversion.
2312 Label conversion_failure;
2313 __ cmpl(rax, Immediate(0x80000000));
2314 __ j(equal, &conversion_failure);
2315
2316 // Smi tag and return.
2317 __ Integer32ToSmi(rax, rax);
2318 __ bind(&smi);
2319 __ ret(2 * kPointerSize);
2320
2321 // Check if the argument is < 2^kMantissaBits.
2322 Label already_round;
2323 __ bind(&conversion_failure);
2324 int64_t kTwoMantissaBits= V8_INT64_C(0x4330000000000000);
2325 __ movq(rbx, kTwoMantissaBits, RelocInfo::NONE64);
2326 __ movq(xmm1, rbx);
2327 __ ucomisd(xmm0, xmm1);
2328 __ j(above_equal, &already_round);
2329
2330 // Save a copy of the argument.
2331 __ movaps(xmm2, xmm0);
2332
2333 // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits.
2334 __ addsd(xmm0, xmm1);
2335 __ subsd(xmm0, xmm1);
2336
2337 // Compare the argument and the tentative result to get the right mask:
2338 // if xmm2 < xmm0:
2339 // xmm2 = 1...1
2340 // else:
2341 // xmm2 = 0...0
2342 __ cmpltsd(xmm2, xmm0);
2343
2344 // Subtract 1 if the argument was less than the tentative result.
2345 int64_t kOne = V8_INT64_C(0x3ff0000000000000);
2346 __ movq(rbx, kOne, RelocInfo::NONE64);
2347 __ movq(xmm1, rbx);
2348 __ andpd(xmm1, xmm2);
2349 __ subsd(xmm0, xmm1);
2350
2351 // Return a new heap number.
2352 __ AllocateHeapNumber(rax, rbx, &slow);
2353 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0);
2354 __ ret(2 * kPointerSize);
2355
2356 // Return the argument (when it's an already round heap number).
2357 __ bind(&already_round);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002358 __ movq(rax, args.GetArgumentOperand(1));
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002359 __ ret(2 * kPointerSize);
2360
2361 // Tail call the full function. We do not have to patch the receiver
2362 // because the function makes no use of it.
2363 __ bind(&slow);
2364 ParameterCount expected(function);
2365 __ InvokeFunction(function, expected, arguments(),
2366 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
2367
2368 __ bind(&miss);
2369 // rcx: function name.
2370 GenerateMissBranch();
2371
2372 // Return the generated code.
2373 return GetCode(type, name);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002374}
2375
2376
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002377Handle<Code> CallStubCompiler::CompileMathAbsCall(
2378 Handle<Object> object,
2379 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002380 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002381 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002382 Handle<String> name,
2383 Code::StubType type) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002384 // ----------- S t a t e -------------
2385 // -- rcx : function name
2386 // -- rsp[0] : return address
2387 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
2388 // -- ...
2389 // -- rsp[(argc + 1) * 8] : receiver
2390 // -----------------------------------
2391
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002392 // If the object is not a JSObject or we got an unexpected number of
2393 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002394 const int argc = arguments().immediate();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002395 StackArgumentsAccessor args(rsp, argc);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002396 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002397
2398 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002399 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002400
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002401 if (cell.is_null()) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002402 __ movq(rdx, args.GetReceiverOperand());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002403 __ JumpIfSmi(rdx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002404 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
2405 name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002406 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002407 ASSERT(cell->value() == *function);
2408 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2409 &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002410 GenerateLoadFunctionFromCell(cell, function, &miss);
2411 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002412 // Load the (only) argument into rax.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002413 __ movq(rax, args.GetArgumentOperand(1));
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002414
2415 // Check if the argument is a smi.
2416 Label not_smi;
2417 STATIC_ASSERT(kSmiTag == 0);
2418 __ JumpIfNotSmi(rax, &not_smi);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002419
danno@chromium.org59400602013-08-13 17:09:37 +00002420 // Branchless abs implementation, refer to below:
2421 // http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002422 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2423 // otherwise.
danno@chromium.org59400602013-08-13 17:09:37 +00002424 __ movq(rbx, rax);
2425 __ sar(rbx, Immediate(kBitsPerPointer - 1));
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002426
2427 // Do bitwise not or do nothing depending on ebx.
danno@chromium.org59400602013-08-13 17:09:37 +00002428 __ xor_(rax, rbx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002429
2430 // Add 1 or do nothing depending on ebx.
danno@chromium.org59400602013-08-13 17:09:37 +00002431 __ subq(rax, rbx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002432
2433 // If the result is still negative, go to the slow case.
2434 // This only happens for the most negative smi.
2435 Label slow;
2436 __ j(negative, &slow);
2437
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002438 __ ret(2 * kPointerSize);
2439
2440 // Check if the argument is a heap number and load its value.
2441 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002442 __ CheckMap(rax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002443 __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
2444
2445 // Check the sign of the argument. If the argument is positive,
2446 // just return it.
2447 Label negative_sign;
2448 const int sign_mask_shift =
2449 (HeapNumber::kExponentOffset - HeapNumber::kValueOffset) * kBitsPerByte;
2450 __ movq(rdi, static_cast<int64_t>(HeapNumber::kSignMask) << sign_mask_shift,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00002451 RelocInfo::NONE64);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002452 __ testq(rbx, rdi);
2453 __ j(not_zero, &negative_sign);
2454 __ ret(2 * kPointerSize);
2455
2456 // If the argument is negative, clear the sign, and return a new
2457 // number. We still have the sign mask in rdi.
2458 __ bind(&negative_sign);
2459 __ xor_(rbx, rdi);
2460 __ AllocateHeapNumber(rax, rdx, &slow);
2461 __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rbx);
2462 __ ret(2 * kPointerSize);
2463
2464 // Tail call the full function. We do not have to patch the receiver
2465 // because the function makes no use of it.
2466 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002467 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002468 ? CALL_AS_FUNCTION
2469 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002470 ParameterCount expected(function);
2471 __ InvokeFunction(function, expected, arguments(),
2472 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002473
2474 __ bind(&miss);
2475 // rcx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002476 GenerateMissBranch();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002477
2478 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002479 return GetCode(type, name);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002480}
2481
2482
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002483Handle<Code> CallStubCompiler::CompileFastApiCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002484 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002485 Handle<Object> object,
2486 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002487 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002488 Handle<JSFunction> function,
2489 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002490 ASSERT(optimization.is_simple_api_call());
2491 // Bail out if object is a global object as we don't want to
2492 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002493 if (object->IsGlobalObject()) return Handle<Code>::null();
2494 if (!cell.is_null()) return Handle<Code>::null();
2495 if (!object->IsJSObject()) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002496 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002497 Handle<JSObject>::cast(object), holder);
2498 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002499
2500 Label miss, miss_before_stack_reserved;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002501 GenerateNameCheck(name, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002503 const int argc = arguments().immediate();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002504 StackArgumentsAccessor args(rsp, argc);
2505 __ movq(rdx, args.GetReceiverOperand());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002506
2507 // Check that the receiver isn't a smi.
2508 __ JumpIfSmi(rdx, &miss_before_stack_reserved);
2509
lrn@chromium.org7516f052011-03-30 08:52:27 +00002510 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002511 __ IncrementCounter(counters->call_const(), 1);
2512 __ IncrementCounter(counters->call_const_fast_api(), 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002513
2514 // Allocate space for v8::Arguments implicit values. Must be initialized
2515 // before calling any runtime function.
2516 __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2517
2518 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002519 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
2520 name, depth, &miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002521
2522 // Move the return address on top of the stack.
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002523 __ movq(rax,
2524 StackOperandForReturnAddress(kFastApiCallArguments * kPointerSize));
2525 __ movq(StackOperandForReturnAddress(0), rax);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002526
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002527 GenerateFastApiCall(masm(), optimization, argc, false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002528
2529 __ bind(&miss);
2530 __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2531
2532 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002533 GenerateMissBranch();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002534
2535 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002536 return GetCode(function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002537}
2538
2539
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002540void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2541 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002542 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002543 CheckType check,
2544 Label* success) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002545 // ----------- S t a t e -------------
2546 // rcx : function name
2547 // rsp[0] : return address
2548 // rsp[8] : argument argc
2549 // rsp[16] : argument argc - 1
2550 // ...
2551 // rsp[argc * 8] : argument 1
2552 // rsp[(argc + 1) * 8] : argument 0 = receiver
2553 // -----------------------------------
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002554 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002555 GenerateNameCheck(name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002556
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002557 StackArgumentsAccessor args(rsp, arguments());
2558 __ movq(rdx, args.GetReceiverOperand());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002559
2560 // Check that the receiver isn't a smi.
2561 if (check != NUMBER_CHECK) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002562 __ JumpIfSmi(rdx, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002563 }
2564
2565 // Make sure that it's okay not to patch the on stack receiver
2566 // unless we're doing a receiver map check.
2567 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2568
lrn@chromium.org7516f052011-03-30 08:52:27 +00002569 Counters* counters = isolate()->counters();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002570 switch (check) {
2571 case RECEIVER_MAP_CHECK:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002572 __ IncrementCounter(counters->call_const(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002573
2574 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002575 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax,
2576 rdi, name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002577
2578 // Patch the receiver on the stack with the global proxy if
2579 // necessary.
2580 if (object->IsGlobalObject()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002581 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002582 __ movq(args.GetReceiverOperand(), rdx);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002583 }
2584 break;
2585
2586 case STRING_CHECK:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002587 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002588 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
2589 __ j(above_equal, &miss);
2590 // Check that the maps starting from the prototype haven't changed.
2591 GenerateDirectLoadGlobalFunctionPrototype(
2592 masm(), Context::STRING_FUNCTION_INDEX, rax, &miss);
2593 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002594 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002595 rax, holder, rbx, rdx, rdi, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002596 break;
2597
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002598 case SYMBOL_CHECK:
2599 // Check that the object is a symbol.
2600 __ CmpObjectType(rdx, SYMBOL_TYPE, rax);
2601 __ j(not_equal, &miss);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002602 // Check that the maps starting from the prototype haven't changed.
2603 GenerateDirectLoadGlobalFunctionPrototype(
2604 masm(), Context::SYMBOL_FUNCTION_INDEX, rax, &miss);
2605 CheckPrototypes(
2606 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2607 rax, holder, rbx, rdx, rdi, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002608 break;
2609
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002610 case NUMBER_CHECK: {
2611 Label fast;
2612 // Check that the object is a smi or a heap number.
2613 __ JumpIfSmi(rdx, &fast);
2614 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax);
2615 __ j(not_equal, &miss);
2616 __ bind(&fast);
2617 // Check that the maps starting from the prototype haven't changed.
2618 GenerateDirectLoadGlobalFunctionPrototype(
2619 masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss);
2620 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002621 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002622 rax, holder, rbx, rdx, rdi, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002623 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002624 }
2625 case BOOLEAN_CHECK: {
2626 Label fast;
2627 // Check that the object is a boolean.
2628 __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
2629 __ j(equal, &fast);
2630 __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
2631 __ j(not_equal, &miss);
2632 __ bind(&fast);
2633 // Check that the maps starting from the prototype haven't changed.
2634 GenerateDirectLoadGlobalFunctionPrototype(
2635 masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
2636 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002637 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002638 rax, holder, rbx, rdx, rdi, name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002639 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002640 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002641 }
2642
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002643 __ jmp(success);
2644
2645 // Handle call cache miss.
2646 __ bind(&miss);
2647 GenerateMissBranch();
2648}
2649
2650
2651void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002652 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002653 ? CALL_AS_FUNCTION
2654 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002655 ParameterCount expected(function);
2656 __ InvokeFunction(function, expected, arguments(),
2657 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002658}
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002659
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002660
2661Handle<Code> CallStubCompiler::CompileCallConstant(
2662 Handle<Object> object,
2663 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002664 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002665 CheckType check,
2666 Handle<JSFunction> function) {
2667 if (HasCustomCallGenerator(function)) {
2668 Handle<Code> code = CompileCustomCall(object, holder,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002669 Handle<PropertyCell>::null(),
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002670 function, Handle<String>::cast(name),
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002671 Code::CONSTANT);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002672 // A null handle means bail out to the regular compiler code below.
2673 if (!code.is_null()) return code;
2674 }
2675
2676 Label success;
2677
2678 CompileHandlerFrontend(object, holder, name, check, &success);
2679 __ bind(&success);
2680 CompileHandlerBackend(function);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002681
2682 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002683 return GetCode(function);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002684}
2685
2686
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002687Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2688 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002689 Handle<Name> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002690 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00002691 // rcx : function name
2692 // rsp[0] : return address
2693 // rsp[8] : argument argc
2694 // rsp[16] : argument argc - 1
2695 // ...
2696 // rsp[argc * 8] : argument 1
2697 // rsp[(argc + 1) * 8] : argument 0 = receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002698 // -----------------------------------
2699 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002700 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002701
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002702
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002703 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002704 LookupPostInterceptor(holder, name, &lookup);
2705
2706 // Get the receiver from the stack.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002707 StackArgumentsAccessor args(rsp, arguments());
2708 __ movq(rdx, args.GetReceiverOperand());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002709
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002710 CallInterceptorCompiler compiler(this, arguments(), rcx, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002711 compiler.Compile(masm(), object, holder, name, &lookup, rdx, rbx, rdi, rax,
2712 &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002713
2714 // Restore receiver.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002715 __ movq(rdx, args.GetReceiverOperand());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002716
2717 // Check that the function really is a function.
ager@chromium.org4af710e2009-09-15 12:20:11 +00002718 __ JumpIfSmi(rax, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002719 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2720 __ j(not_equal, &miss);
2721
2722 // Patch the receiver on the stack with the global proxy if
2723 // necessary.
2724 if (object->IsGlobalObject()) {
2725 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002726 __ movq(args.GetReceiverOperand(), rdx);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002727 }
2728
2729 // Invoke the function.
2730 __ movq(rdi, rax);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002731 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002732 ? CALL_AS_FUNCTION
2733 : CALL_AS_METHOD;
2734 __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
2735 NullCallWrapper(), call_kind);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002736
2737 // Handle load cache miss.
2738 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002739 GenerateMissBranch();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002740
2741 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002742 return GetCode(Code::INTERCEPTOR, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002743}
2744
2745
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002746Handle<Code> CallStubCompiler::CompileCallGlobal(
2747 Handle<JSObject> object,
2748 Handle<GlobalObject> holder,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002749 Handle<PropertyCell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002750 Handle<JSFunction> function,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002751 Handle<Name> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002752 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00002753 // rcx : function name
2754 // rsp[0] : return address
2755 // rsp[8] : argument argc
2756 // rsp[16] : argument argc - 1
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002757 // ...
ager@chromium.org5c838252010-02-19 08:53:10 +00002758 // rsp[argc * 8] : argument 1
2759 // rsp[(argc + 1) * 8] : argument 0 = receiver
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002760 // -----------------------------------
2761
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002762 if (HasCustomCallGenerator(function)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002763 Handle<Code> code = CompileCustomCall(
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002764 object, holder, cell, function, Handle<String>::cast(name),
2765 Code::NORMAL);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002766 // A null handle means bail out to the regular compiler code below.
2767 if (!code.is_null()) return code;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002768 }
2769
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002770 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002771 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002772
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002773 StackArgumentsAccessor args(rsp, arguments());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002774 GenerateGlobalReceiverCheck(object, holder, name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002775 GenerateLoadFunctionFromCell(cell, function, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002776
2777 // Patch the receiver on the stack with the global proxy.
2778 if (object->IsGlobalObject()) {
2779 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002780 __ movq(args.GetReceiverOperand(), rdx);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002781 }
2782
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002783 // Set up the context (function already in rdi).
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002784 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
2785
2786 // Jump to the cached code (tail call).
lrn@chromium.org7516f052011-03-30 08:52:27 +00002787 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002788 __ IncrementCounter(counters->call_global_inline(), 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002789 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002790 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002791 ? CALL_AS_FUNCTION
2792 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002793 // We call indirectly through the code field in the function to
2794 // allow recompilation to take effect without changing any of the
2795 // call sites.
2796 __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
2797 __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION,
2798 NullCallWrapper(), call_kind);
2799
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002800 // Handle call cache miss.
2801 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002802 __ IncrementCounter(counters->call_global_inline_miss(), 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002803 GenerateMissBranch();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002804
2805 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002806 return GetCode(Code::NORMAL, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002807}
2808
2809
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002810Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002811 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002812 Handle<JSObject> holder,
danno@chromium.orgbee51992013-07-10 14:57:15 +00002813 Handle<Name> name,
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002814 Handle<ExecutableAccessorInfo> callback) {
danno@chromium.orgbee51992013-07-10 14:57:15 +00002815 Label success;
2816 HandlerFrontend(object, receiver(), holder, name, &success);
2817 __ bind(&success);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002818
danno@chromium.org59400602013-08-13 17:09:37 +00002819 __ PopReturnAddressTo(scratch1());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002820 __ push(receiver());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002821 __ Push(callback); // callback info
danno@chromium.orgbee51992013-07-10 14:57:15 +00002822 __ Push(name);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002823 __ push(value());
danno@chromium.org59400602013-08-13 17:09:37 +00002824 __ PushReturnAddressFrom(scratch1());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002825
2826 // Do tail-call to the runtime system.
2827 ExternalReference store_callback_property =
lrn@chromium.org7516f052011-03-30 08:52:27 +00002828 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002829 __ TailCallExternalReference(store_callback_property, 4, 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002830
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002831 // Return the generated code.
danno@chromium.orgbee51992013-07-10 14:57:15 +00002832 return GetCode(kind(), Code::CALLBACKS, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002833}
2834
2835
dslomov@chromium.org639bac02013-09-09 11:58:54 +00002836Handle<Code> StoreStubCompiler::CompileStoreCallback(
2837 Handle<JSObject> object,
2838 Handle<JSObject> holder,
2839 Handle<Name> name,
2840 const CallOptimization& call_optimization) {
2841 Label success;
2842 HandlerFrontend(object, receiver(), holder, name, &success);
2843 __ bind(&success);
2844
2845 Register values[] = { value() };
2846 GenerateFastApiCall(
2847 masm(), call_optimization, receiver(), scratch3(), 1, values);
2848
2849 // Return the generated code.
2850 return GetCode(kind(), Code::CALLBACKS, name);
2851}
2852
2853
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002854#undef __
2855#define __ ACCESS_MASM(masm)
2856
2857
2858void StoreStubCompiler::GenerateStoreViaSetter(
2859 MacroAssembler* masm,
2860 Handle<JSFunction> setter) {
2861 // ----------- S t a t e -------------
2862 // -- rax : value
2863 // -- rcx : name
2864 // -- rdx : receiver
2865 // -- rsp[0] : return address
2866 // -----------------------------------
2867 {
2868 FrameScope scope(masm, StackFrame::INTERNAL);
2869
2870 // Save value register, so we can restore it later.
2871 __ push(rax);
2872
2873 if (!setter.is_null()) {
2874 // Call the JavaScript setter with receiver and value on the stack.
2875 __ push(rdx);
2876 __ push(rax);
2877 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002878 ParameterCount expected(setter);
2879 __ InvokeFunction(setter, expected, actual,
2880 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002881 } else {
2882 // If we generate a global code snippet for deoptimization only, remember
2883 // the place to continue after deoptimization.
2884 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2885 }
2886
2887 // We have to return the passed value, not the return value of the setter.
2888 __ pop(rax);
2889
2890 // Restore context register.
2891 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2892 }
2893 __ ret(0);
2894}
2895
2896
2897#undef __
2898#define __ ACCESS_MASM(masm())
2899
2900
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002901Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002902 Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002903 Handle<Name> name) {
danno@chromium.org59400602013-08-13 17:09:37 +00002904 __ PopReturnAddressTo(scratch1());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002905 __ push(receiver());
2906 __ push(this->name());
2907 __ push(value());
2908 __ Push(Smi::FromInt(strict_mode()));
danno@chromium.org59400602013-08-13 17:09:37 +00002909 __ PushReturnAddressFrom(scratch1());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002910
2911 // Do tail-call to the runtime system.
2912 ExternalReference store_ic_property =
lrn@chromium.org7516f052011-03-30 08:52:27 +00002913 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002914 __ TailCallExternalReference(store_ic_property, 4, 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002915
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002916 // Return the generated code.
danno@chromium.orgbee51992013-07-10 14:57:15 +00002917 return GetCode(kind(), Code::INTERCEPTOR, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002918}
2919
2920
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002921Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2922 MapHandleList* receiver_maps,
2923 CodeHandleList* handler_stubs,
2924 MapHandleList* transitioned_maps) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002925 Label miss;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002926 __ JumpIfSmi(receiver(), &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002927
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002928 __ movq(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002929 int receiver_count = receiver_maps->length();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002930 for (int i = 0; i < receiver_count; ++i) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002931 // Check map and tail call if there's a match
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002932 __ Cmp(scratch1(), receiver_maps->at(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002933 if (transitioned_maps->at(i).is_null()) {
2934 __ j(equal, handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002935 } else {
2936 Label next_map;
2937 __ j(not_equal, &next_map, Label::kNear);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002938 __ movq(transition_map(),
2939 transitioned_maps->at(i),
2940 RelocInfo::EMBEDDED_OBJECT);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002941 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002942 __ bind(&next_map);
2943 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002944 }
2945
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002946 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002947
2948 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002949
2950 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002951 return GetICCode(
2952 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002953}
2954
2955
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002956Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002957 Handle<JSObject> object,
2958 Handle<JSObject> last,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002959 Handle<Name> name,
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002960 Handle<GlobalObject> global) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002961 Label success;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002962
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002963 NonexistentHandlerFrontend(object, last, name, &success, global);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002964
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002965 __ bind(&success);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002966 // Return undefined if maps of the full prototype chain are still the
2967 // same and no global property with this name contains a value.
2968 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2969 __ ret(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002970
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002971 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00002972 return GetCode(kind(), Code::NONEXISTENT, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002973}
2974
2975
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002976Register* LoadStubCompiler::registers() {
2977 // receiver, name, scratch1, scratch2, scratch3, scratch4.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002978 static Register registers[] = { rax, rcx, rdx, rbx, rdi, r8 };
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002979 return registers;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002980}
2981
2982
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002983Register* KeyedLoadStubCompiler::registers() {
2984 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2985 static Register registers[] = { rdx, rax, rbx, rcx, rdi, r8 };
2986 return registers;
2987}
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002988
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002989
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002990Register* StoreStubCompiler::registers() {
2991 // receiver, name, value, scratch1, scratch2, scratch3.
2992 static Register registers[] = { rdx, rcx, rax, rbx, rdi, r8 };
2993 return registers;
2994}
2995
2996
2997Register* KeyedStoreStubCompiler::registers() {
2998 // receiver, name, value, scratch1, scratch2, scratch3.
2999 static Register registers[] = { rdx, rcx, rax, rbx, rdi, r8 };
3000 return registers;
3001}
3002
3003
ulan@chromium.org750145a2013-03-07 15:14:13 +00003004void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003005 Register name_reg,
3006 Label* miss) {
3007 __ Cmp(name_reg, name);
3008 __ j(not_equal, miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003009}
3010
3011
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003012void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
3013 Register name_reg,
3014 Label* miss) {
3015 __ Cmp(name_reg, name);
3016 __ j(not_equal, miss);
3017}
3018
3019
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003020#undef __
3021#define __ ACCESS_MASM(masm)
3022
3023
3024void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00003025 Register receiver,
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003026 Handle<JSFunction> getter) {
3027 // ----------- S t a t e -------------
3028 // -- rax : receiver
3029 // -- rcx : name
3030 // -- rsp[0] : return address
3031 // -----------------------------------
3032 {
3033 FrameScope scope(masm, StackFrame::INTERNAL);
3034
3035 if (!getter.is_null()) {
3036 // Call the JavaScript getter with the receiver on the stack.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00003037 __ push(receiver);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003038 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003039 ParameterCount expected(getter);
3040 __ InvokeFunction(getter, expected, actual,
3041 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003042 } else {
3043 // If we generate a global code snippet for deoptimization only, remember
3044 // the place to continue after deoptimization.
3045 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
3046 }
3047
3048 // Restore context register.
3049 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3050 }
3051 __ ret(0);
3052}
3053
3054
3055#undef __
3056#define __ ACCESS_MASM(masm())
3057
3058
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003059Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3060 Handle<JSObject> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003061 Handle<GlobalObject> global,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00003062 Handle<PropertyCell> cell,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003063 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003064 bool is_dont_delete) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003065 Label success, miss;
3066 // TODO(verwaest): Directly store to rax. Currently we cannot do this, since
3067 // rax is used as receiver(), which we would otherwise clobber before a
3068 // potential miss.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003069
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003070 __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
3071 HandlerFrontendHeader(
3072 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003073
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003074 // Get the value from the cell.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003075 __ Move(rbx, cell);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00003076 __ movq(rbx, FieldOperand(rbx, PropertyCell::kValueOffset));
whesse@chromium.orge90029b2010-08-02 11:52:17 +00003077
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003078 // Check for deleted property if property can actually be deleted.
3079 if (!is_dont_delete) {
3080 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
3081 __ j(equal, &miss);
3082 } else if (FLAG_debug_code) {
3083 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
danno@chromium.org59400602013-08-13 17:09:37 +00003084 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003085 }
3086
danno@chromium.orgbee51992013-07-10 14:57:15 +00003087 HandlerFrontendFooter(name, &success, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003088 __ bind(&success);
3089
lrn@chromium.org7516f052011-03-30 08:52:27 +00003090 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003091 __ IncrementCounter(counters->named_load_global_stub(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003092 __ movq(rax, rbx);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003093 __ ret(0);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003094
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003095 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003096 return GetICCode(kind(), Code::NORMAL, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003097}
3098
3099
danno@chromium.orgbee51992013-07-10 14:57:15 +00003100Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003101 MapHandleList* receiver_maps,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003102 CodeHandleList* handlers,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003103 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003104 Code::StubType type,
3105 IcCheckType check) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003106 Label miss;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003107
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003108 if (check == PROPERTY) {
3109 GenerateNameCheck(name, this->name(), &miss);
3110 }
3111
3112 __ JumpIfSmi(receiver(), &miss);
3113 Register map_reg = scratch1();
3114 __ movq(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003115 int receiver_count = receiver_maps->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003116 int number_of_handled_maps = 0;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003117 for (int current = 0; current < receiver_count; ++current) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003118 Handle<Map> map = receiver_maps->at(current);
3119 if (!map->is_deprecated()) {
3120 number_of_handled_maps++;
3121 // Check map and tail call if there's a match
3122 __ Cmp(map_reg, receiver_maps->at(current));
3123 __ j(equal, handlers->at(current), RelocInfo::CODE_TARGET);
3124 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003125 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003126 ASSERT(number_of_handled_maps > 0);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003127
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003128 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003129 TailCallBuiltin(masm(), MissBuiltin(kind()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003130
3131 // Return the generated code.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003132 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00003133 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
ulan@chromium.org750145a2013-03-07 15:14:13 +00003134 return GetICCode(kind(), type, name, state);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003135}
3136
3137
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003138#undef __
3139#define __ ACCESS_MASM(masm)
3140
3141
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003142void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3143 MacroAssembler* masm) {
3144 // ----------- S t a t e -------------
3145 // -- rax : key
3146 // -- rdx : receiver
3147 // -- rsp[0] : return address
3148 // -----------------------------------
3149 Label slow, miss_force_generic;
3150
3151 // This stub is meant to be tail-jumped to, the receiver must already
3152 // have been verified by the caller to not be a smi.
3153
3154 __ JumpIfNotSmi(rax, &miss_force_generic);
3155 __ SmiToInteger32(rbx, rax);
3156 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
3157
3158 // Check whether the elements is a number dictionary.
3159 // rdx: receiver
3160 // rax: key
3161 // rbx: key as untagged int32
3162 // rcx: elements
3163 __ LoadFromNumberDictionary(&slow, rcx, rax, rbx, r9, rdi, rax);
3164 __ ret(0);
3165
3166 __ bind(&slow);
3167 // ----------- S t a t e -------------
3168 // -- rax : key
3169 // -- rdx : receiver
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00003170 // -- rsp[0] : return address
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003171 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003172 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003173
3174 __ bind(&miss_force_generic);
3175 // ----------- S t a t e -------------
3176 // -- rax : key
3177 // -- rdx : receiver
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00003178 // -- rsp[0] : return address
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003179 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003180 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003181}
3182
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003183
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003184#undef __
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003185
3186} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003187
3188#endif // V8_TARGET_ARCH_X64