blob: a7faf9b663dd0410dd9598acc6c6b385ed3b90d2 [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
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_X64)
31
ager@chromium.org5aa501c2009-06-23 07:57:28 +000032#include "ic-inl.h"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000033#include "codegen.h"
ager@chromium.org5aa501c2009-06-23 07:57:28 +000034#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
kasperl@chromium.orge959c182009-07-27 08:59:04 +000039#define __ ACCESS_MASM(masm)
40
41
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000042static void ProbeTable(Isolate* isolate,
43 MacroAssembler* masm,
kasperl@chromium.orge959c182009-07-27 08:59:04 +000044 Code::Flags flags,
45 StubCache::Table table,
ulan@chromium.org812308e2012-02-29 15:58:45 +000046 Register receiver,
kasperl@chromium.orge959c182009-07-27 08:59:04 +000047 Register name,
ulan@chromium.org812308e2012-02-29 15:58:45 +000048 // The offset is scaled by 4, based on
49 // kHeapObjectTagSize, which is two bits
kasperl@chromium.orge959c182009-07-27 08:59:04 +000050 Register offset) {
ulan@chromium.org812308e2012-02-29 15:58:45 +000051 // We need to scale up the pointer by 2 because the offset is scaled by less
52 // than the pointer size.
53 ASSERT(kPointerSizeLog2 == kHeapObjectTagSize + 1);
54 ScaleFactor scale_factor = times_2;
55
56 ASSERT_EQ(24, sizeof(StubCache::Entry));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000057 // The offset register holds the entry offset times four (due to masking
58 // and shifting optimizations).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000059 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
ulan@chromium.org812308e2012-02-29 15:58:45 +000060 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
kasperl@chromium.orge959c182009-07-27 08:59:04 +000061 Label miss;
62
ulan@chromium.org812308e2012-02-29 15:58:45 +000063 // Multiply by 3 because there are 3 fields per entry (name, code, map).
64 __ lea(offset, Operand(offset, offset, times_2, 0));
65
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000066 __ LoadAddress(kScratchRegister, key_offset);
ulan@chromium.org812308e2012-02-29 15:58:45 +000067
kasperl@chromium.orge959c182009-07-27 08:59:04 +000068 // Check that the key in the entry matches the name.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000069 // Multiply entry offset by 16 to get the entry address. Since the
70 // offset register already holds the entry offset times four, multiply
71 // by a further four.
ulan@chromium.org812308e2012-02-29 15:58:45 +000072 __ cmpl(name, Operand(kScratchRegister, offset, scale_factor, 0));
kasperl@chromium.orge959c182009-07-27 08:59:04 +000073 __ j(not_equal, &miss);
ulan@chromium.org812308e2012-02-29 15:58:45 +000074
75 // Get the map entry from the cache.
76 // Use key_offset + kPointerSize * 2, rather than loading map_offset.
kasperl@chromium.orge959c182009-07-27 08:59:04 +000077 __ movq(kScratchRegister,
ulan@chromium.org812308e2012-02-29 15:58:45 +000078 Operand(kScratchRegister, offset, scale_factor, kPointerSize * 2));
79 __ cmpq(kScratchRegister, FieldOperand(receiver, HeapObject::kMapOffset));
80 __ j(not_equal, &miss);
81
82 // Get the code entry from the cache.
83 __ LoadAddress(kScratchRegister, value_offset);
84 __ movq(kScratchRegister,
85 Operand(kScratchRegister, offset, scale_factor, 0));
86
kasperl@chromium.orge959c182009-07-27 08:59:04 +000087 // Check that the flags match what we're looking for.
88 __ movl(offset, FieldOperand(kScratchRegister, Code::kFlagsOffset));
89 __ and_(offset, Immediate(~Code::kFlagsNotUsedInLookup));
90 __ cmpl(offset, Immediate(flags));
91 __ j(not_equal, &miss);
92
ulan@chromium.org812308e2012-02-29 15:58:45 +000093#ifdef DEBUG
94 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
95 __ jmp(&miss);
96 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
97 __ jmp(&miss);
98 }
99#endif
100
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000101 // Jump to the first instruction in the code stub.
102 __ addq(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag));
103 __ jmp(kScratchRegister);
104
105 __ bind(&miss);
106}
107
108
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000109// Helper function used to check that the dictionary doesn't contain
110// the property. This function may return false negatives, so miss_label
111// must always call a backup property check that is complete.
112// This function is safe to call if the receiver has fast properties.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000113// Name must be unique and receiver must be a heap object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000114static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
115 Label* miss_label,
116 Register receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000117 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000118 Register r0,
119 Register r1) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000120 ASSERT(name->IsUniqueName());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000121 Counters* counters = masm->isolate()->counters();
122 __ IncrementCounter(counters->negative_lookups(), 1);
123 __ IncrementCounter(counters->negative_lookups_miss(), 1);
124
125 __ movq(r0, FieldOperand(receiver, HeapObject::kMapOffset));
126
127 const int kInterceptorOrAccessCheckNeededMask =
128 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
129
130 // Bail out if the receiver has a named interceptor or requires access checks.
131 __ testb(FieldOperand(r0, Map::kBitFieldOffset),
132 Immediate(kInterceptorOrAccessCheckNeededMask));
133 __ j(not_zero, miss_label);
134
135 // Check that receiver is a JSObject.
136 __ CmpInstanceType(r0, FIRST_SPEC_OBJECT_TYPE);
137 __ j(below, miss_label);
138
139 // Load properties array.
140 Register properties = r0;
141 __ movq(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
142
143 // Check that the properties array is a dictionary.
144 __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset),
145 Heap::kHashTableMapRootIndex);
146 __ j(not_equal, miss_label);
147
148 Label done;
ulan@chromium.org750145a2013-03-07 15:14:13 +0000149 NameDictionaryLookupStub::GenerateNegativeLookup(masm,
150 miss_label,
151 &done,
152 properties,
153 name,
154 r1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000155 __ bind(&done);
156 __ DecrementCounter(counters->negative_lookups_miss(), 1);
157}
158
159
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000160void StubCache::GenerateProbe(MacroAssembler* masm,
161 Code::Flags flags,
162 Register receiver,
163 Register name,
164 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000165 Register extra,
ulan@chromium.org812308e2012-02-29 15:58:45 +0000166 Register extra2,
167 Register extra3) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000168 Isolate* isolate = masm->isolate();
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000169 Label miss;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000170 USE(extra); // The register extra is not used on the X64 platform.
171 USE(extra2); // The register extra2 is not used on the X64 platform.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000172 USE(extra3); // The register extra2 is not used on the X64 platform.
173 // Make sure that code is valid. The multiplying code relies on the
174 // entry size being 24.
175 ASSERT(sizeof(Entry) == 24);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000176
177 // Make sure the flags do not name a specific type.
178 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
179
180 // Make sure that there are no register conflicts.
181 ASSERT(!scratch.is(receiver));
182 ASSERT(!scratch.is(name));
183
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000184 // Check scratch register is valid, extra and extra2 are unused.
185 ASSERT(!scratch.is(no_reg));
186 ASSERT(extra2.is(no_reg));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000187 ASSERT(extra3.is(no_reg));
188
189 Counters* counters = masm->isolate()->counters();
190 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000191
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000192 // Check that the receiver isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000193 __ JumpIfSmi(receiver, &miss);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000194
195 // Get the map of the receiver and compute the hash.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000196 __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000197 // Use only the low 32 bits of the map pointer.
198 __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
199 __ xor_(scratch, Immediate(flags));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000200 // We mask out the last two bits because they are not part of the hash and
201 // they are always 01 for maps. Also in the two 'and' instructions below.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000202 __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
203
204 // Probe the primary table.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000205 ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000206
207 // Primary miss: Compute hash for secondary probe.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000208 __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000209 __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
210 __ xor_(scratch, Immediate(flags));
211 __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
212 __ subl(scratch, name);
213 __ addl(scratch, Immediate(flags));
214 __ and_(scratch, Immediate((kSecondaryTableSize - 1) << kHeapObjectTagSize));
215
216 // Probe the secondary table.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000217 ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000218
219 // Cache miss: Fall-through and let caller handle the miss by
220 // entering the runtime system.
221 __ bind(&miss);
ulan@chromium.org812308e2012-02-29 15:58:45 +0000222 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000223}
224
225
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000226void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
227 int index,
228 Register prototype) {
229 // Load the global or builtins object from the current context.
230 __ movq(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000231 Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
232 // Load the native context from the global or builtins object.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000233 __ movq(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000234 FieldOperand(prototype, GlobalObject::kNativeContextOffset));
235 // Load the function from the native context.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000236 __ movq(prototype, Operand(prototype, Context::SlotOffset(index)));
237 // Load the initial map. The global functions all have initial maps.
238 __ movq(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000239 FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000240 // Load the prototype from the initial map.
241 __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
242}
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000243
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000244
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000245void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000246 MacroAssembler* masm,
247 int index,
248 Register prototype,
249 Label* miss) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000250 Isolate* isolate = masm->isolate();
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000251 // Check we're still in the same context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000252 __ Move(prototype, isolate->global_object());
253 __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)),
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000254 prototype);
255 __ j(not_equal, miss);
256 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000257 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000258 JSFunction::cast(isolate->native_context()->get(index)));
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000259 // Load its initial map. The global functions all have initial maps.
260 __ Move(prototype, Handle<Map>(function->initial_map()));
261 // Load the prototype from the initial map.
262 __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000263}
264
265
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000266void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
267 Register receiver,
268 Register scratch,
269 Label* miss_label) {
270 // Check that the receiver isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000271 __ JumpIfSmi(receiver, miss_label);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000272
273 // Check that the object is a JS array.
274 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
275 __ j(not_equal, miss_label);
276
277 // Load length directly from the JS array.
278 __ movq(rax, FieldOperand(receiver, JSArray::kLengthOffset));
279 __ ret(0);
280}
281
282
283// Generate code to check if an object is a string. If the object is
284// a string, the map's instance type is left in the scratch register.
285static void GenerateStringCheck(MacroAssembler* masm,
286 Register receiver,
287 Register scratch,
288 Label* smi,
289 Label* non_string_object) {
290 // Check that the object isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000291 __ JumpIfSmi(receiver, smi);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000292
293 // Check that the object is a string.
294 __ movq(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
295 __ movzxbq(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000296 STATIC_ASSERT(kNotStringTag != 0);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000297 __ testl(scratch, Immediate(kNotStringTag));
298 __ j(not_zero, non_string_object);
299}
300
301
302void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
303 Register receiver,
ager@chromium.org5c838252010-02-19 08:53:10 +0000304 Register scratch1,
305 Register scratch2,
ager@chromium.org378b34e2011-01-28 08:04:38 +0000306 Label* miss,
307 bool support_wrappers) {
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.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000312 GenerateStringCheck(masm, receiver, scratch1, miss,
313 support_wrappers ? &check_wrapper : miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000314
315 // Load length directly from the string.
ager@chromium.orgac091b72010-05-05 07:34:42 +0000316 __ movq(rax, FieldOperand(receiver, String::kLengthOffset));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000317 __ ret(0);
318
ager@chromium.org378b34e2011-01-28 08:04:38 +0000319 if (support_wrappers) {
320 // Check if the object is a JSValue wrapper.
321 __ bind(&check_wrapper);
322 __ cmpl(scratch1, Immediate(JS_VALUE_TYPE));
323 __ j(not_equal, miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000324
ager@chromium.org378b34e2011-01-28 08:04:38 +0000325 // Check if the wrapped value is a string and load the length
326 // directly if it is.
327 __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
328 GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
329 __ movq(rax, FieldOperand(scratch2, String::kLengthOffset));
330 __ ret(0);
331 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000332}
333
334
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000335void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
336 Register receiver,
337 Register result,
338 Register scratch,
339 Label* miss_label) {
340 __ TryGetFunctionPrototype(receiver, result, miss_label);
341 if (!result.is(rax)) __ movq(rax, result);
342 __ ret(0);
343}
344
345
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000346void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
347 Register dst,
348 Register src,
349 bool inobject,
350 int index,
351 Representation representation) {
352 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000353 int offset = index * kPointerSize;
354 if (!inobject) {
355 // Calculate the offset into the properties array.
356 offset = offset + FixedArray::kHeaderSize;
357 __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
358 src = dst;
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000359 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000360 __ movq(dst, FieldOperand(src, offset));
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000361}
362
363
364static void PushInterceptorArguments(MacroAssembler* masm,
365 Register receiver,
366 Register holder,
367 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000368 Handle<JSObject> holder_obj) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000369 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000370 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
371 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
372 __ Move(kScratchRegister, interceptor);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000373 __ push(kScratchRegister);
374 __ push(receiver);
375 __ push(holder);
376 __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000377 __ PushAddress(ExternalReference::isolate_address(masm->isolate()));
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());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000392 __ Set(rax, 6);
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.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000401static const int kFastApiCallArguments = 4;
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 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +0000413 __ movq(scratch, Operand(rsp, 0));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000414 __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
ager@chromium.orgac091b72010-05-05 07:34:42 +0000415 __ movq(Operand(rsp, 0), scratch);
416 __ Move(scratch, Smi::FromInt(0));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000417 for (int i = 1; i <= kFastApiCallArguments; i++) {
418 __ movq(Operand(rsp, i * kPointerSize), scratch);
419 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000420}
421
422
423// Undoes the effects of ReserveSpaceForFastApiCall.
424static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
425 // ----------- S t a t e -------------
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000426 // -- rsp[0] : return address.
427 // -- rsp[8] : last fast api call extra argument.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000428 // -- ...
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000429 // -- rsp[kFastApiCallArguments * 8] : first fast api call extra argument.
430 // -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal
431 // frame.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000432 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +0000433 __ movq(scratch, Operand(rsp, 0));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000434 __ movq(Operand(rsp, kFastApiCallArguments * kPointerSize), scratch);
435 __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000436}
437
438
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000439// Generates call to API function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000440static void GenerateFastApiCall(MacroAssembler* masm,
441 const CallOptimization& optimization,
442 int argc) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000443 // ----------- S t a t e -------------
444 // -- rsp[0] : return address
445 // -- rsp[8] : object passing the type check
446 // (last fast api call extra argument,
447 // set by CheckPrototypes)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000448 // -- rsp[16] : api function
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000449 // (first fast api call extra argument)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000450 // -- rsp[24] : api call data
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000451 // -- rsp[32] : isolate
452 // -- rsp[40] : last argument
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000453 // -- ...
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000454 // -- rsp[(argc + 4) * 8] : first argument
455 // -- rsp[(argc + 5) * 8] : receiver
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000456 // -----------------------------------
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000457 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000458 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000459 __ LoadHeapObject(rdi, function);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000460 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
461
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000462 // Pass the additional arguments.
463 __ movq(Operand(rsp, 2 * kPointerSize), rdi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000464 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000465 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000466 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
467 __ Move(rcx, api_call_info);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000468 __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000469 __ movq(Operand(rsp, 3 * kPointerSize), rbx);
470 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000471 __ Move(Operand(rsp, 3 * kPointerSize), call_data);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000472 }
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000473 __ movq(kScratchRegister,
474 ExternalReference::isolate_address(masm->isolate()));
jkummerow@chromium.org3ee08a62012-04-13 13:01:33 +0000475 __ movq(Operand(rsp, 4 * kPointerSize), kScratchRegister);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000476
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000477 // Prepare arguments.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000478 __ lea(rbx, Operand(rsp, 4 * kPointerSize));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000479
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000480#if defined(__MINGW64__)
481 Register arguments_arg = rcx;
482#elif defined(_WIN64)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000483 // Win64 uses first register--rcx--for returned value.
484 Register arguments_arg = rdx;
485#else
486 Register arguments_arg = rdi;
487#endif
488
489 // Allocate the v8::Arguments structure in the arguments' space since
490 // it's not controlled by GC.
491 const int kApiStackSpace = 4;
492
493 __ PrepareCallApiFunction(kApiStackSpace);
494
495 __ movq(StackSpaceOperand(0), rbx); // v8::Arguments::implicit_args_.
496 __ addq(rbx, Immediate(argc * kPointerSize));
497 __ movq(StackSpaceOperand(1), rbx); // v8::Arguments::values_.
498 __ Set(StackSpaceOperand(2), argc); // v8::Arguments::length_.
499 // v8::Arguments::is_construct_call_.
500 __ Set(StackSpaceOperand(3), 0);
501
502 // v8::InvocationCallback's argument.
503 __ lea(arguments_arg, StackSpaceOperand(0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000504
505 // Function address is a foreign pointer outside V8's heap.
506 Address function_address = v8::ToCData<Address>(api_call_info->callback());
507 __ CallApiFunctionAndReturn(function_address,
508 argc + kFastApiCallArguments + 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000509}
510
511
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000512class CallInterceptorCompiler BASE_EMBEDDED {
513 public:
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000514 CallInterceptorCompiler(StubCompiler* stub_compiler,
515 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000516 Register name,
517 Code::ExtraICState extra_ic_state)
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000518 : stub_compiler_(stub_compiler),
519 arguments_(arguments),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000520 name_(name),
521 extra_ic_state_(extra_ic_state) {}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000522
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000523 void Compile(MacroAssembler* masm,
524 Handle<JSObject> object,
525 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000526 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000527 LookupResult* lookup,
528 Register receiver,
529 Register scratch1,
530 Register scratch2,
531 Register scratch3,
532 Label* miss) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000533 ASSERT(holder->HasNamedInterceptor());
534 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
535
536 // Check that the receiver isn't a smi.
537 __ JumpIfSmi(receiver, miss);
538
539 CallOptimization optimization(lookup);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000540 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000541 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
542 holder, lookup, name, optimization, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000543 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000544 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
545 name, holder, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000546 }
547 }
548
549 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000550 void CompileCacheable(MacroAssembler* masm,
551 Handle<JSObject> object,
552 Register receiver,
553 Register scratch1,
554 Register scratch2,
555 Register scratch3,
556 Handle<JSObject> interceptor_holder,
557 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000558 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000559 const CallOptimization& optimization,
560 Label* miss_label) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000561 ASSERT(optimization.is_constant_call());
ager@chromium.org5c838252010-02-19 08:53:10 +0000562 ASSERT(!lookup->holder()->IsGlobalObject());
563
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000564 int depth1 = kInvalidProtoDepth;
565 int depth2 = kInvalidProtoDepth;
566 bool can_do_fast_api_call = false;
567 if (optimization.is_simple_api_call() &&
568 !lookup->holder()->IsGlobalObject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000569 depth1 = optimization.GetPrototypeDepthOfExpectedType(
570 object, interceptor_holder);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000571 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000572 depth2 = optimization.GetPrototypeDepthOfExpectedType(
573 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000574 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000575 can_do_fast_api_call =
576 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000577 }
578
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000579 Counters* counters = masm->isolate()->counters();
580 __ IncrementCounter(counters->call_const_interceptor(), 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000581
582 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000583 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000584 ReserveSpaceForFastApiCall(masm, scratch1);
585 }
586
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000587 // Check that the maps from receiver to interceptor's holder
588 // haven't changed and thus we can invoke interceptor.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000589 Label miss_cleanup;
590 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
591 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000592 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
593 scratch1, scratch2, scratch3,
594 name, depth1, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000595
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000596 // Invoke an interceptor and if it provides a value,
597 // branch to |regular_invoke|.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000598 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000599 LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
600 &regular_invoke);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000601
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000602 // Interceptor returned nothing for this property. Try to use cached
603 // constant function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000604
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000605 // Check that the maps from interceptor's holder to constant function's
606 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000607 if (*interceptor_holder != lookup->holder()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000608 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000609 Handle<JSObject>(lookup->holder()),
610 scratch1, scratch2, scratch3,
611 name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000612 } else {
613 // CheckPrototypes has a side effect of fetching a 'holder'
614 // for API (object which is instanceof for the signature). It's
615 // safe to omit it here, as if present, it should be fetched
616 // by the previous CheckPrototypes.
617 ASSERT(depth2 == kInvalidProtoDepth);
618 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000619
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000620 // Invoke function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000621 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000622 GenerateFastApiCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000623 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000624 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
625 ? CALL_AS_FUNCTION
626 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000627 Handle<JSFunction> fun = optimization.constant_function();
ulan@chromium.orgbebf0742013-04-24 12:21:36 +0000628 ParameterCount expected(fun);
629 __ InvokeFunction(fun, expected, arguments_,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000630 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000631 }
632
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000633 // Deferred code for fast API call case---clean preallocated space.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000634 if (can_do_fast_api_call) {
635 __ bind(&miss_cleanup);
636 FreeSpaceForFastApiCall(masm, scratch1);
637 __ jmp(miss_label);
638 }
639
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000640 // Invoke a regular function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000641 __ bind(&regular_invoke);
642 if (can_do_fast_api_call) {
643 FreeSpaceForFastApiCall(masm, scratch1);
644 }
645 }
646
647 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000648 Handle<JSObject> object,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000649 Register receiver,
650 Register scratch1,
651 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000652 Register scratch3,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000653 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000654 Handle<JSObject> interceptor_holder,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000655 Label* miss_label) {
656 Register holder =
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000657 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000658 scratch1, scratch2, scratch3,
659 name, miss_label);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000660
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000661 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000662 // Save the name_ register across the call.
663 __ push(name_);
664
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000665 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000666
667 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000668 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
669 masm->isolate()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000670 6);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000671
672 // Restore the name_ register.
673 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000674
675 // Leave the internal frame.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000676 }
677
678 void LoadWithInterceptor(MacroAssembler* masm,
679 Register receiver,
680 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000681 Handle<JSObject> holder_obj,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000682 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000683 {
684 FrameScope scope(masm, StackFrame::INTERNAL);
685 __ push(holder); // Save the holder.
686 __ push(name_); // Save the name.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000687
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000688 CompileCallLoadPropertyWithInterceptor(masm,
689 receiver,
690 holder,
691 name_,
692 holder_obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000693
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000694 __ pop(name_); // Restore the name.
695 __ pop(receiver); // Restore the holder.
696 // Leave the internal frame.
697 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000698
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000699 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000700 __ j(not_equal, interceptor_succeeded);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000701 }
702
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000703 StubCompiler* stub_compiler_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000704 const ParameterCount& arguments_;
ager@chromium.org5c838252010-02-19 08:53:10 +0000705 Register name_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000706 Code::ExtraICState extra_ic_state_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000707};
708
709
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000710void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
711 Label* label,
712 Handle<Name> name) {
713 if (!label->is_unused()) {
714 __ bind(label);
715 __ Move(this->name(), name);
716 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000717}
718
719
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000720// Generate code to check that a global property cell is empty. Create
721// the property cell at compilation time if no cell exists for the
722// property.
723static void GenerateCheckPropertyCell(MacroAssembler* masm,
724 Handle<GlobalObject> global,
725 Handle<Name> name,
726 Register scratch,
727 Label* miss) {
728 Handle<JSGlobalPropertyCell> cell =
729 GlobalObject::EnsurePropertyCell(global, name);
730 ASSERT(cell->value()->IsTheHole());
731 __ Move(scratch, cell);
732 __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
733 masm->isolate()->factory()->the_hole_value());
734 __ j(not_equal, miss);
735}
736
737
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000738// Both name_reg and receiver_reg are preserved on jumps to miss_label,
739// but may be destroyed if store is successful.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000740void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
741 Handle<JSObject> object,
742 LookupResult* lookup,
743 Handle<Map> transition,
744 Handle<Name> name,
745 Register receiver_reg,
746 Register name_reg,
747 Register value_reg,
748 Register scratch1,
749 Register scratch2,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000750 Register unused,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000751 Label* miss_label,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000752 Label* miss_restore_name,
753 Label* slow) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000754 // Check that the map of the object hasn't changed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000755 __ CheckMap(receiver_reg, Handle<Map>(object->map()),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000756 miss_label, DO_SMI_CHECK, REQUIRE_EXACT_MAP);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000757
758 // Perform global security token check if needed.
759 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000760 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
761 }
762
danno@chromium.orgf005df62013-04-30 16:36:45 +0000763 int descriptor = transition->LastAdded();
764 DescriptorArray* descriptors = transition->instance_descriptors();
765 PropertyDetails details = descriptors->GetDetails(descriptor);
766 Representation representation = details.representation();
767 ASSERT(!representation.IsNone());
768
769 // Ensure no transitions to deprecated maps are followed.
770 __ CheckMapDeprecated(transition, scratch1, miss_label);
771
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000772 // Check that we are allowed to write this.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000773 if (object->GetPrototype()->IsJSObject()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000774 JSObject* holder;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000775 // holder == object indicates that no property was found.
776 if (lookup->holder() != *object) {
777 holder = lookup->holder();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000778 } else {
779 // Find the top object.
780 holder = *object;
781 do {
782 holder = JSObject::cast(holder->GetPrototype());
783 } while (holder->GetPrototype()->IsJSObject());
784 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000785 Register holder_reg = CheckPrototypes(
786 object, receiver_reg, Handle<JSObject>(holder), name_reg,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000787 scratch1, scratch2, name, miss_restore_name, SKIP_RECEIVER);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000788 // If no property was found, and the holder (the last object in the
789 // prototype chain) is in slow mode, we need to do a negative lookup on the
790 // holder.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000791 if (lookup->holder() == *object) {
792 if (holder->IsJSGlobalObject()) {
793 GenerateCheckPropertyCell(
794 masm,
795 Handle<GlobalObject>(GlobalObject::cast(holder)),
796 name,
797 scratch1,
798 miss_restore_name);
799 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
800 GenerateDictionaryNegativeLookup(
801 masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
802 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000803 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000804 }
805
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000806 Register storage_reg = name_reg;
807
808 if (FLAG_track_fields && representation.IsSmi()) {
809 __ JumpIfNotSmi(value_reg, miss_restore_name);
810 } else if (FLAG_track_double_fields && representation.IsDouble()) {
811 Label do_store, heap_number;
812 __ AllocateHeapNumber(storage_reg, scratch1, slow);
813
814 __ JumpIfNotSmi(value_reg, &heap_number);
815 __ SmiToInteger32(scratch1, value_reg);
816 __ cvtlsi2sd(xmm0, scratch1);
817 __ jmp(&do_store);
818
819 __ bind(&heap_number);
820 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
821 miss_restore_name, DONT_DO_SMI_CHECK, REQUIRE_EXACT_MAP);
822 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
823
824 __ bind(&do_store);
825 __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0);
826 }
827
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000828 // Stub never generated for non-global objects that require access
829 // checks.
830 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
831
832 // Perform map transition for the receiver if necessary.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000833 if (object->map()->unused_property_fields() == 0) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000834 // The properties must be extended before we can store the value.
835 // We jump to a runtime call that extends the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000836 __ pop(scratch1); // Return address.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000837 __ push(receiver_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000838 __ Push(transition);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000839 __ push(value_reg);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000840 __ push(scratch1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000841 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000842 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
843 masm->isolate()),
844 3,
845 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000846 return;
847 }
848
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000849 // Update the map of the object.
850 __ Move(scratch1, transition);
851 __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000852
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000853 // Update the write barrier for the map field.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000854 __ RecordWriteField(receiver_reg,
855 HeapObject::kMapOffset,
856 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000857 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000858 kDontSaveFPRegs,
859 OMIT_REMEMBERED_SET,
860 OMIT_SMI_CHECK);
861
862 int index = transition->instance_descriptors()->GetFieldIndex(
863 transition->LastAdded());
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000864
865 // Adjust for the number of properties stored in the object. Even in the
866 // face of a transition we can use the old map here because the size of the
867 // object and the number of in-object properties is not going to change.
868 index -= object->map()->inobject_properties();
869
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000870 // TODO(verwaest): Share this code as a code stub.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000871 if (index < 0) {
872 // Set the property straight into the object.
873 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000874 if (FLAG_track_double_fields && representation.IsDouble()) {
875 __ movq(FieldOperand(receiver_reg, offset), storage_reg);
876 } else {
877 __ movq(FieldOperand(receiver_reg, offset), value_reg);
878 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000879
danno@chromium.orgf005df62013-04-30 16:36:45 +0000880 if (!FLAG_track_fields || !representation.IsSmi()) {
881 // Update the write barrier for the array address.
882 // Pass the value being stored in the now unused name_reg.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000883 if (!FLAG_track_double_fields || !representation.IsDouble()) {
884 __ movq(name_reg, value_reg);
885 } else {
886 ASSERT(storage_reg.is(name_reg));
887 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000888 __ RecordWriteField(
889 receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs);
890 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000891 } else {
892 // Write to the properties array.
893 int offset = index * kPointerSize + FixedArray::kHeaderSize;
894 // Get the properties array (optimistically).
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000895 __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000896 if (FLAG_track_double_fields && representation.IsDouble()) {
897 __ movq(FieldOperand(scratch1, offset), storage_reg);
898 } else {
899 __ movq(FieldOperand(scratch1, offset), value_reg);
900 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000901
danno@chromium.orgf005df62013-04-30 16:36:45 +0000902 if (!FLAG_track_fields || !representation.IsSmi()) {
903 // Update the write barrier for the array address.
904 // Pass the value being stored in the now unused name_reg.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000905 if (!FLAG_track_double_fields || !representation.IsDouble()) {
906 __ movq(name_reg, value_reg);
907 } else {
908 ASSERT(storage_reg.is(name_reg));
909 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000910 __ RecordWriteField(
911 scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs);
912 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000913 }
914
915 // Return the value (register rax).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000916 ASSERT(value_reg.is(rax));
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000917 __ ret(0);
918}
919
920
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000921// Both name_reg and receiver_reg are preserved on jumps to miss_label,
922// but may be destroyed if store is successful.
923void StubCompiler::GenerateStoreField(MacroAssembler* masm,
924 Handle<JSObject> object,
925 LookupResult* lookup,
926 Register receiver_reg,
927 Register name_reg,
928 Register value_reg,
929 Register scratch1,
930 Register scratch2,
931 Label* miss_label) {
932 // Check that the map of the object hasn't changed.
933 __ CheckMap(receiver_reg, Handle<Map>(object->map()),
934 miss_label, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
935
936 // Perform global security token check if needed.
937 if (object->IsJSGlobalProxy()) {
938 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
939 }
940
941 // Stub never generated for non-global objects that require access
942 // checks.
943 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
944
945 int index = lookup->GetFieldIndex().field_index();
946
947 // Adjust for the number of properties stored in the object. Even in the
948 // face of a transition we can use the old map here because the size of the
949 // object and the number of in-object properties is not going to change.
950 index -= object->map()->inobject_properties();
951
danno@chromium.orgf005df62013-04-30 16:36:45 +0000952 Representation representation = lookup->representation();
953 ASSERT(!representation.IsNone());
954 if (FLAG_track_fields && representation.IsSmi()) {
955 __ JumpIfNotSmi(value_reg, miss_label);
956 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000957 // Load the double storage.
958 if (index < 0) {
959 int offset = object->map()->instance_size() + (index * kPointerSize);
960 __ movq(scratch1, FieldOperand(receiver_reg, offset));
961 } else {
962 __ movq(scratch1,
963 FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
964 int offset = index * kPointerSize + FixedArray::kHeaderSize;
965 __ movq(scratch1, FieldOperand(scratch1, offset));
966 }
967
968 // Store the value into the storage.
969 Label do_store, heap_number;
970 __ JumpIfNotSmi(value_reg, &heap_number);
971 __ SmiToInteger32(scratch2, value_reg);
972 __ cvtlsi2sd(xmm0, scratch2);
973 __ jmp(&do_store);
974
975 __ bind(&heap_number);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000976 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
977 miss_label, DONT_DO_SMI_CHECK, REQUIRE_EXACT_MAP);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000978 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
979
danno@chromium.orgf005df62013-04-30 16:36:45 +0000980 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000981 __ movsd(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0);
982 // Return the value (register rax).
983 ASSERT(value_reg.is(rax));
984 __ ret(0);
985 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000986 }
987
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000988 // TODO(verwaest): Share this code as a code stub.
989 if (index < 0) {
990 // Set the property straight into the object.
991 int offset = object->map()->instance_size() + (index * kPointerSize);
992 __ movq(FieldOperand(receiver_reg, offset), value_reg);
993
danno@chromium.orgf005df62013-04-30 16:36:45 +0000994 if (!FLAG_track_fields || !representation.IsSmi()) {
995 // Update the write barrier for the array address.
996 // Pass the value being stored in the now unused name_reg.
997 __ movq(name_reg, value_reg);
998 __ RecordWriteField(
999 receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs);
1000 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001001 } else {
1002 // Write to the properties array.
1003 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1004 // Get the properties array (optimistically).
1005 __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
1006 __ movq(FieldOperand(scratch1, offset), value_reg);
1007
danno@chromium.orgf005df62013-04-30 16:36:45 +00001008 if (!FLAG_track_fields || !representation.IsSmi()) {
1009 // Update the write barrier for the array address.
1010 // Pass the value being stored in the now unused name_reg.
1011 __ movq(name_reg, value_reg);
1012 __ RecordWriteField(
1013 scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs);
1014 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001015 }
1016
1017 // Return the value (register rax).
1018 ASSERT(value_reg.is(rax));
1019 __ ret(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001020}
1021
1022
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001023// Calls GenerateCheckPropertyCell for each global object in the prototype chain
1024// from object to (but not including) holder.
1025static void GenerateCheckPropertyCells(MacroAssembler* masm,
1026 Handle<JSObject> object,
1027 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001028 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001029 Register scratch,
1030 Label* miss) {
1031 Handle<JSObject> current = object;
1032 while (!current.is_identical_to(holder)) {
1033 if (current->IsGlobalObject()) {
1034 GenerateCheckPropertyCell(masm,
1035 Handle<GlobalObject>::cast(current),
1036 name,
1037 scratch,
1038 miss);
1039 }
1040 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1041 }
1042}
1043
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001044
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001045void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001046 __ jmp(code, RelocInfo::CODE_TARGET);
1047}
1048
1049
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001050#undef __
1051#define __ ACCESS_MASM((masm()))
1052
1053
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001054Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1055 Register object_reg,
1056 Handle<JSObject> holder,
1057 Register holder_reg,
1058 Register scratch1,
1059 Register scratch2,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001060 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001061 int save_at_depth,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001062 Label* miss,
1063 PrototypeCheckType check) {
1064 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001065 // Make sure there's no overlap between holder and object registers.
1066 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1067 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1068 && !scratch2.is(scratch1));
1069
1070 // Keep track of the current object in register reg. On the first
1071 // iteration, reg is an alias for object_reg, on later iterations,
1072 // it is an alias for holder_reg.
1073 Register reg = object_reg;
1074 int depth = 0;
1075
1076 if (save_at_depth == depth) {
1077 __ movq(Operand(rsp, kPointerSize), object_reg);
1078 }
1079
1080 // Check the maps in the prototype chain.
1081 // Traverse the prototype chain from the object and do map checks.
1082 Handle<JSObject> current = object;
1083 while (!current.is_identical_to(holder)) {
1084 ++depth;
1085
1086 // Only global objects and objects that do not require access
1087 // checks are allowed in stubs.
1088 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1089
1090 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1091 if (!current->HasFastProperties() &&
1092 !current->IsJSGlobalObject() &&
1093 !current->IsJSGlobalProxy()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001094 if (!name->IsUniqueName()) {
1095 ASSERT(name->IsString());
1096 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001097 }
1098 ASSERT(current->property_dictionary()->FindEntry(*name) ==
ulan@chromium.org750145a2013-03-07 15:14:13 +00001099 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001100
1101 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1102 scratch1, scratch2);
1103
1104 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1105 reg = holder_reg; // From now on the object will be in holder_reg.
1106 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1107 } else {
1108 bool in_new_space = heap()->InNewSpace(*prototype);
1109 Handle<Map> current_map(current->map());
1110 if (in_new_space) {
1111 // Save the map in scratch1 for later.
1112 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001113 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001114 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1115 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
1116 ALLOW_ELEMENT_TRANSITION_MAPS);
1117 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001118
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001119 // Check access rights to the global object. This has to happen after
1120 // the map check so that we know that the object is actually a global
1121 // object.
1122 if (current->IsJSGlobalProxy()) {
1123 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1124 }
1125 reg = holder_reg; // From now on the object will be in holder_reg.
1126
1127 if (in_new_space) {
1128 // The prototype is in new space; we cannot store a reference to it
1129 // in the code. Load it from the map.
1130 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1131 } else {
1132 // The prototype is in old space; load it directly.
1133 __ Move(reg, prototype);
1134 }
1135 }
1136
1137 if (save_at_depth == depth) {
1138 __ movq(Operand(rsp, kPointerSize), reg);
1139 }
1140
1141 // Go to the next object in the prototype chain.
1142 current = prototype;
1143 }
1144 ASSERT(current.is_identical_to(holder));
1145
1146 // Log the check depth.
1147 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1148
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001149 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1150 // Check the holder map.
1151 __ CheckMap(reg, Handle<Map>(holder->map()),
1152 miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
1153 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001154
1155 // Perform security check for access to the global object.
1156 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1157 if (current->IsJSGlobalProxy()) {
1158 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1159 }
1160
1161 // If we've skipped any global objects, it's not enough to verify that
1162 // their maps haven't changed. We also need to check that the property
1163 // cell for the property is still empty.
1164 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1165
1166 // Return the register containing the holder.
1167 return reg;
1168}
1169
1170
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001171void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1172 Label* miss) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001173 if (!miss->is_unused()) {
1174 __ jmp(success);
1175 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001176 TailCallBuiltin(masm(), MissBuiltin(kind()));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001177 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001178}
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001179
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001180
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001181Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1182 Handle<JSObject> object,
1183 Register object_reg,
1184 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001185 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001186 Label* success,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001187 Handle<ExecutableAccessorInfo> callback) {
1188 Label miss;
1189
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001190 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001191
1192 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1193 ASSERT(!reg.is(scratch2()));
1194 ASSERT(!reg.is(scratch3()));
1195 ASSERT(!reg.is(scratch4()));
1196
1197 // Load the properties dictionary.
1198 Register dictionary = scratch4();
1199 __ movq(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset));
1200
1201 // Probe the dictionary.
1202 Label probe_done;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001203 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1204 &miss,
1205 &probe_done,
1206 dictionary,
1207 this->name(),
1208 scratch2(),
1209 scratch3());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001210 __ bind(&probe_done);
1211
1212 // If probing finds an entry in the dictionary, scratch3 contains the
1213 // index into the dictionary. Check that the value is the callback.
1214 Register index = scratch3();
1215 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +00001216 NameDictionary::kHeaderSize +
1217 NameDictionary::kElementsStartIndex * kPointerSize;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001218 const int kValueOffset = kElementsStartOffset + kPointerSize;
1219 __ movq(scratch2(),
1220 Operand(dictionary, index, times_pointer_size,
1221 kValueOffset - kHeapObjectTag));
1222 __ movq(scratch3(), callback, RelocInfo::EMBEDDED_OBJECT);
1223 __ cmpq(scratch2(), scratch3());
1224 __ j(not_equal, &miss);
1225 }
1226
1227 HandlerFrontendFooter(success, &miss);
1228 return reg;
1229}
1230
1231
1232void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1233 Handle<JSObject> object,
1234 Handle<JSObject> last,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001235 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001236 Label* success,
1237 Handle<GlobalObject> global) {
1238 Label miss;
1239
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001240 HandlerFrontendHeader(object, receiver(), last, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001241
1242 // If the last object in the prototype chain is a global object,
1243 // check that the global property cell is empty.
1244 if (!global.is_null()) {
1245 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1246 }
1247
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001248 HandlerFrontendFooter(success, &miss);
1249}
1250
1251
1252void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1253 Handle<JSObject> holder,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001254 PropertyIndex field,
1255 Representation representation) {
1256 if (!reg.is(receiver())) __ movq(receiver(), reg);
1257 if (kind() == Code::LOAD_IC) {
1258 LoadFieldStub stub(field.is_inobject(holder),
1259 field.translate(holder),
1260 representation);
1261 GenerateTailCall(masm(), stub.GetCode(isolate()));
1262 } else {
1263 KeyedLoadFieldStub stub(field.is_inobject(holder),
1264 field.translate(holder),
1265 representation);
1266 GenerateTailCall(masm(), stub.GetCode(isolate()));
1267 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001268}
1269
1270
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001271void BaseLoadStubCompiler::GenerateLoadCallback(
1272 Register reg,
1273 Handle<ExecutableAccessorInfo> callback) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001274 // Insert additional parameters into the stack frame above return address.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001275 ASSERT(!scratch2().is(reg));
1276 __ pop(scratch2()); // Get return address to place it below.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001277
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001278 __ push(receiver()); // receiver
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001279 __ push(reg); // holder
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001280 if (heap()->InNewSpace(callback->data())) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001281 __ Move(scratch1(), callback);
1282 __ push(FieldOperand(scratch1(),
1283 ExecutableAccessorInfo::kDataOffset)); // data
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001284 } else {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001285 __ Push(Handle<Object>(callback->data(), isolate()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001286 }
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001287 __ PushAddress(ExternalReference::isolate_address(isolate())); // isolate
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001288 __ push(name()); // name
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001289 // Save a pointer to where we pushed the arguments pointer. This will be
1290 // passed as the const ExecutableAccessorInfo& to the C++ callback.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001291
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001292#if defined(__MINGW64__)
1293 Register accessor_info_arg = rdx;
1294 Register name_arg = rcx;
1295#elif defined(_WIN64)
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001296 // Win64 uses first register--rcx--for returned value.
1297 Register accessor_info_arg = r8;
1298 Register name_arg = rdx;
1299#else
1300 Register accessor_info_arg = rsi;
1301 Register name_arg = rdi;
1302#endif
1303
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001304 ASSERT(!name_arg.is(scratch2()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001305 __ movq(name_arg, rsp);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001306 __ push(scratch2()); // Restore return address.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001307
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001308 // 4 elements array for v8::Arguments::values_ and handler for name.
1309 const int kStackSpace = 5;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001310
1311 // Allocate v8::AccessorInfo in non-GCed stack space.
1312 const int kArgStackSpace = 1;
1313
1314 __ PrepareCallApiFunction(kArgStackSpace);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001315 __ lea(rax, Operand(name_arg, 4 * kPointerSize));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001316
1317 // v8::AccessorInfo::args_.
1318 __ movq(StackSpaceOperand(0), rax);
1319
1320 // The context register (rsi) has been saved in PrepareCallApiFunction and
1321 // could be used to pass arguments.
1322 __ lea(accessor_info_arg, StackSpaceOperand(0));
1323
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001324 Address getter_address = v8::ToCData<Address>(callback->getter());
1325 __ CallApiFunctionAndReturn(getter_address, kStackSpace);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001326}
1327
1328
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001329void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001330 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001331 __ LoadHeapObject(rax, value);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001332 __ ret(0);
1333}
1334
1335
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001336void BaseLoadStubCompiler::GenerateLoadInterceptor(
1337 Register holder_reg,
1338 Handle<JSObject> object,
1339 Handle<JSObject> interceptor_holder,
1340 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001341 Handle<Name> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001342 ASSERT(interceptor_holder->HasNamedInterceptor());
1343 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1344
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001345 // So far the most popular follow ups for interceptor loads are FIELD
1346 // and CALLBACKS, so inline only them, other cases may be added
1347 // later.
1348 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001349 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001350 if (lookup->IsField()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001351 compile_followup_inline = true;
1352 } else if (lookup->type() == CALLBACKS &&
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001353 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1354 ExecutableAccessorInfo* callback =
1355 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001356 compile_followup_inline = callback->getter() != NULL &&
1357 callback->IsCompatibleReceiver(*object);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001358 }
1359 }
1360
1361 if (compile_followup_inline) {
1362 // Compile the interceptor call, followed by inline code to load the
1363 // property from further up the prototype chain if the call fails.
1364 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001365 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001366
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001367 // Preserve the receiver register explicitly whenever it is different from
1368 // the holder and it is needed should the interceptor return without any
1369 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1370 // the FIELD case might cause a miss during the prototype check.
1371 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001372 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001373 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1374
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001375 // Save necessary data before invoking an interceptor.
1376 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001377 {
1378 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001379
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001380 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001381 __ push(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001382 }
1383 __ push(holder_reg);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001384 __ push(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001385
1386 // Invoke an interceptor. Note: map checks from receiver to
1387 // interceptor's holder has been compiled before (see a caller
1388 // of this method.)
1389 CompileCallLoadPropertyWithInterceptor(masm(),
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001390 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001391 holder_reg,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001392 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001393 interceptor_holder);
1394
1395 // Check if interceptor provided a value for property. If it's
1396 // the case, return immediately.
1397 Label interceptor_failed;
1398 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
1399 __ j(equal, &interceptor_failed);
1400 frame_scope.GenerateLeaveFrame();
1401 __ ret(0);
1402
1403 __ bind(&interceptor_failed);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001404 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001405 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001406 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001407 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001408 }
1409
1410 // Leave the internal frame.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001411 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001412
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001413 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001414 } else { // !compile_followup_inline
1415 // Call the runtime system to load the interceptor.
1416 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001417 __ pop(scratch2()); // save old return address
1418 PushInterceptorArguments(masm(), receiver(), holder_reg,
1419 this->name(), interceptor_holder);
1420 __ push(scratch2()); // restore old return address
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001421
1422 ExternalReference ref = ExternalReference(
lrn@chromium.org7516f052011-03-30 08:52:27 +00001423 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001424 __ TailCallExternalReference(ref, 6, 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001425 }
1426}
1427
1428
ulan@chromium.org750145a2013-03-07 15:14:13 +00001429void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001430 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001431 __ Cmp(rcx, name);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001432 __ j(not_equal, miss);
1433 }
1434}
1435
1436
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001437void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1438 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001439 Handle<Name> name,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001440 Label* miss) {
1441 ASSERT(holder->IsGlobalObject());
1442
1443 // Get the number of arguments.
1444 const int argc = arguments().immediate();
1445
1446 // Get the receiver from the stack.
1447 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1448
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001449
1450 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001451 __ JumpIfSmi(rdx, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001452 CheckPrototypes(object, rdx, holder, rbx, rax, rdi, name, miss);
1453}
1454
1455
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001456void CallStubCompiler::GenerateLoadFunctionFromCell(
1457 Handle<JSGlobalPropertyCell> cell,
1458 Handle<JSFunction> function,
1459 Label* miss) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001460 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001461 __ Move(rdi, cell);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001462 __ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset));
1463
1464 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001465 if (heap()->InNewSpace(*function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001466 // We can't embed a pointer to a function in new space so we have
1467 // to verify that the shared function info is unchanged. This has
1468 // the nice side effect that multiple closures based on the same
1469 // function can all use this call IC. Before we load through the
1470 // function, we have to verify that it still is a function.
1471 __ JumpIfSmi(rdi, miss);
1472 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax);
1473 __ j(not_equal, miss);
1474
1475 // Check the shared function info. Make sure it hasn't changed.
1476 __ Move(rax, Handle<SharedFunctionInfo>(function->shared()));
1477 __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001478 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001479 __ Cmp(rdi, function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001480 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001481 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001482}
1483
1484
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001485void CallStubCompiler::GenerateMissBranch() {
1486 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001487 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1488 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001489 extra_state_);
1490 __ Jump(code, RelocInfo::CODE_TARGET);
1491}
1492
1493
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001494Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1495 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001496 PropertyIndex index,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001497 Handle<Name> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001498 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001499 // rcx : function name
1500 // rsp[0] : return address
1501 // rsp[8] : argument argc
1502 // rsp[16] : argument argc - 1
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001503 // ...
ager@chromium.org5c838252010-02-19 08:53:10 +00001504 // rsp[argc * 8] : argument 1
1505 // rsp[(argc + 1) * 8] : argument 0 = receiver
1506 // -----------------------------------
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001507 Label miss;
1508
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001509 GenerateNameCheck(name, &miss);
1510
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001511 // Get the receiver from the stack.
1512 const int argc = arguments().immediate();
1513 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1514
1515 // Check that the receiver isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001516 __ JumpIfSmi(rdx, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001517
1518 // Do the right check and compute the holder register.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001519 Register reg = CheckPrototypes(object, rdx, holder, rbx, rax, rdi,
1520 name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001521
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001522 GenerateFastPropertyLoad(masm(), rdi, reg, index.is_inobject(holder),
1523 index.translate(holder), Representation::Tagged());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001524
1525 // Check that the function really is a function.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001526 __ JumpIfSmi(rdi, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001527 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rbx);
1528 __ j(not_equal, &miss);
1529
1530 // Patch the receiver on the stack with the global proxy if
1531 // necessary.
1532 if (object->IsGlobalObject()) {
1533 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
1534 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
1535 }
1536
1537 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001538 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001539 ? CALL_AS_FUNCTION
1540 : CALL_AS_METHOD;
1541 __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
1542 NullCallWrapper(), call_kind);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001543
1544 // Handle call cache miss.
1545 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001546 GenerateMissBranch();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001547
1548 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001549 return GetCode(Code::FIELD, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001550}
1551
1552
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001553Handle<Code> CallStubCompiler::CompileArrayPushCall(
1554 Handle<Object> object,
1555 Handle<JSObject> holder,
1556 Handle<JSGlobalPropertyCell> cell,
1557 Handle<JSFunction> function,
1558 Handle<String> name) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001559 // ----------- S t a t e -------------
1560 // -- rcx : name
1561 // -- rsp[0] : return address
1562 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1563 // -- ...
1564 // -- rsp[(argc + 1) * 8] : receiver
1565 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +00001566
1567 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001568 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001569
1570 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001571 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001572
ager@chromium.orgac091b72010-05-05 07:34:42 +00001573 // Get the receiver from the stack.
1574 const int argc = arguments().immediate();
1575 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1576
1577 // Check that the receiver isn't a smi.
1578 __ JumpIfSmi(rdx, &miss);
1579
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001580 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
1581 name, &miss);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001582
1583 if (argc == 0) {
1584 // Noop, return the length.
1585 __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset));
1586 __ ret((argc + 1) * kPointerSize);
1587 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001588 Label call_builtin;
1589
ager@chromium.orgac091b72010-05-05 07:34:42 +00001590 if (argc == 1) { // Otherwise fall through to call builtin.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001591 Label attempt_to_grow_elements, with_write_barrier, check_double;
ager@chromium.orgac091b72010-05-05 07:34:42 +00001592
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001593 // Get the elements array of the object.
1594 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
1595
1596 // Check that the elements are in fast mode and writable.
1597 __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
1598 factory()->fixed_array_map());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001599 __ j(not_equal, &check_double);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001600
ager@chromium.orgac091b72010-05-05 07:34:42 +00001601 // Get the array's length into rax and calculate new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001602 __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001603 STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001604 __ addl(rax, Immediate(argc));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001605
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001606 // Get the elements' length into rcx.
1607 __ SmiToInteger32(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001608
1609 // Check if we could survive without allocation.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001610 __ cmpl(rax, rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001611 __ j(greater, &attempt_to_grow_elements);
1612
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001613 // Check if value is a smi.
1614 __ movq(rcx, Operand(rsp, argc * kPointerSize));
1615 __ JumpIfNotSmi(rcx, &with_write_barrier);
1616
ager@chromium.orgac091b72010-05-05 07:34:42 +00001617 // Save new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001618 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001619
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001620 // Store the value.
1621 __ movq(FieldOperand(rdi,
1622 rax,
1623 times_pointer_size,
1624 FixedArray::kHeaderSize - argc * kPointerSize),
1625 rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001626
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001627 __ Integer32ToSmi(rax, rax); // Return new length as smi.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001628 __ ret((argc + 1) * kPointerSize);
1629
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001630 __ bind(&check_double);
1631
1632 // Check that the elements are in double mode.
1633 __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
1634 factory()->fixed_double_array_map());
1635 __ j(not_equal, &call_builtin);
1636
1637 // Get the array's length into rax and calculate new length.
1638 __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset));
1639 STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue);
1640 __ addl(rax, Immediate(argc));
1641
1642 // Get the elements' length into rcx.
1643 __ SmiToInteger32(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
1644
1645 // Check if we could survive without allocation.
1646 __ cmpl(rax, rcx);
1647 __ j(greater, &call_builtin);
1648
1649 __ movq(rcx, Operand(rsp, argc * kPointerSize));
1650 __ StoreNumberToDoubleElements(
1651 rcx, rdi, rax, xmm0, &call_builtin, argc * kDoubleSize);
1652
1653 // Save new length.
1654 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
1655 __ Integer32ToSmi(rax, rax); // Return new length as smi.
1656 __ ret((argc + 1) * kPointerSize);
1657
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001658 __ bind(&with_write_barrier);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001659
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001660 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
1661
1662 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1663 Label fast_object, not_fast_object;
1664 __ CheckFastObjectElements(rbx, &not_fast_object, Label::kNear);
1665 __ jmp(&fast_object);
1666 // In case of fast smi-only, convert to fast object, otherwise bail out.
1667 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001668 __ CheckFastSmiElements(rbx, &call_builtin);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001669 __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset),
1670 factory()->heap_number_map());
1671 __ j(equal, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001672 // rdx: receiver
1673 // rbx: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001674
1675 Label try_holey_map;
1676 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001677 FAST_ELEMENTS,
1678 rbx,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001679 rdi,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001680 &try_holey_map);
1681
1682 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001683 GenerateMapChangeElementsTransition(masm(),
1684 DONT_TRACK_ALLOCATION_SITE,
1685 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001686 // Restore edi.
1687 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
1688 __ jmp(&fast_object);
1689
1690 __ bind(&try_holey_map);
1691 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1692 FAST_HOLEY_ELEMENTS,
1693 rbx,
1694 rdi,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001695 &call_builtin);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001696 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001697 GenerateMapChangeElementsTransition(masm(),
1698 DONT_TRACK_ALLOCATION_SITE,
1699 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001700 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001701 __ bind(&fast_object);
1702 } else {
1703 __ CheckFastObjectElements(rbx, &call_builtin);
1704 }
1705
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001706 // Save new length.
1707 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001708
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001709 // Store the value.
1710 __ lea(rdx, FieldOperand(rdi,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001711 rax, times_pointer_size,
1712 FixedArray::kHeaderSize - argc * kPointerSize));
1713 __ movq(Operand(rdx, 0), rcx);
1714
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001715 __ RecordWrite(rdi, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001716 OMIT_SMI_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001717
1718 __ Integer32ToSmi(rax, rax); // Return new length as smi.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001719 __ ret((argc + 1) * kPointerSize);
1720
1721 __ bind(&attempt_to_grow_elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001722 if (!FLAG_inline_new) {
1723 __ jmp(&call_builtin);
1724 }
1725
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001726 __ movq(rbx, Operand(rsp, argc * kPointerSize));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001727 // Growing elements that are SMI-only requires special handling in case
1728 // the new element is non-Smi. For now, delegate to the builtin.
1729 Label no_fast_elements_check;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001730 __ JumpIfSmi(rbx, &no_fast_elements_check);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001731 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
1732 __ CheckFastObjectElements(rcx, &call_builtin, Label::kFar);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001733 __ bind(&no_fast_elements_check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001734
ager@chromium.orgac091b72010-05-05 07:34:42 +00001735 ExternalReference new_space_allocation_top =
lrn@chromium.org7516f052011-03-30 08:52:27 +00001736 ExternalReference::new_space_allocation_top_address(isolate());
ager@chromium.orgac091b72010-05-05 07:34:42 +00001737 ExternalReference new_space_allocation_limit =
lrn@chromium.org7516f052011-03-30 08:52:27 +00001738 ExternalReference::new_space_allocation_limit_address(isolate());
ager@chromium.orgac091b72010-05-05 07:34:42 +00001739
1740 const int kAllocationDelta = 4;
1741 // Load top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001742 __ Load(rcx, new_space_allocation_top);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001743
1744 // Check if it's the end of elements.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001745 __ lea(rdx, FieldOperand(rdi,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001746 rax, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001747 FixedArray::kHeaderSize - argc * kPointerSize));
1748 __ cmpq(rdx, rcx);
1749 __ j(not_equal, &call_builtin);
1750 __ addq(rcx, Immediate(kAllocationDelta * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 Operand limit_operand =
1752 masm()->ExternalOperand(new_space_allocation_limit);
1753 __ cmpq(rcx, limit_operand);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001754 __ j(above, &call_builtin);
1755
1756 // We fit and could grow elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001757 __ Store(new_space_allocation_top, rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001758
1759 // Push the argument...
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001760 __ movq(Operand(rdx, 0), rbx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001761 // ... and fill the rest with holes.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001762 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001763 for (int i = 1; i < kAllocationDelta; i++) {
1764 __ movq(Operand(rdx, i * kPointerSize), kScratchRegister);
1765 }
1766
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001767 // We know the elements array is in new space so we don't need the
1768 // remembered set, but we just pushed a value onto it so we may have to
1769 // tell the incremental marker to rescan the object that we just grew. We
1770 // don't need to worry about the holes because they are in old space and
1771 // already marked black.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001772 __ RecordWrite(rdi, rdx, rbx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001773
ager@chromium.orgac091b72010-05-05 07:34:42 +00001774 // Restore receiver to rdx as finish sequence assumes it's here.
1775 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1776
1777 // Increment element's and array's sizes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001778 __ SmiAddConstant(FieldOperand(rdi, FixedArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001779 Smi::FromInt(kAllocationDelta));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001780
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001781 // Make new length a smi before returning it.
1782 __ Integer32ToSmi(rax, rax);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001783 __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001784
ager@chromium.orgac091b72010-05-05 07:34:42 +00001785 __ ret((argc + 1) * kPointerSize);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001786 }
1787
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001788 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001790 isolate()),
ager@chromium.orgac091b72010-05-05 07:34:42 +00001791 argc + 1,
1792 1);
1793 }
1794
1795 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001796 GenerateMissBranch();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001797
1798 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001799 return GetCode(function);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001800}
1801
1802
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001803Handle<Code> CallStubCompiler::CompileArrayPopCall(
1804 Handle<Object> object,
1805 Handle<JSObject> holder,
1806 Handle<JSGlobalPropertyCell> cell,
1807 Handle<JSFunction> function,
1808 Handle<String> name) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001809 // ----------- S t a t e -------------
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001810 // -- rcx : name
1811 // -- rsp[0] : return address
1812 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
ager@chromium.orgac091b72010-05-05 07:34:42 +00001813 // -- ...
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001814 // -- rsp[(argc + 1) * 8] : receiver
ager@chromium.orgac091b72010-05-05 07:34:42 +00001815 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +00001816
1817 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001818 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001819
1820 Label miss, return_undefined, call_builtin;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001821 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001822
ager@chromium.orgac091b72010-05-05 07:34:42 +00001823 // Get the receiver from the stack.
1824 const int argc = arguments().immediate();
1825 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1826
1827 // Check that the receiver isn't a smi.
1828 __ JumpIfSmi(rdx, &miss);
1829
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001830 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
1831 name, &miss);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001832
1833 // Get the elements array of the object.
1834 __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
1835
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001836 // Check that the elements are in fast mode and writable.
1837 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
1838 Heap::kFixedArrayMapRootIndex);
1839 __ j(not_equal, &call_builtin);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001840
1841 // Get the array's length into rcx and calculate new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001842 __ SmiToInteger32(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
1843 __ subl(rcx, Immediate(1));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001844 __ j(negative, &return_undefined);
1845
1846 // Get the last element.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001847 __ LoadRoot(r9, Heap::kTheHoleValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001848 __ movq(rax, FieldOperand(rbx,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001849 rcx, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001850 FixedArray::kHeaderSize));
1851 // Check if element is already the hole.
1852 __ cmpq(rax, r9);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001853 // If so, call slow-case to also check prototypes for value.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001854 __ j(equal, &call_builtin);
1855
1856 // Set the array's length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001857 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001858
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001859 // Fill with the hole and return original value.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001860 __ movq(FieldOperand(rbx,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001861 rcx, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001862 FixedArray::kHeaderSize),
1863 r9);
1864 __ ret((argc + 1) * kPointerSize);
1865
1866 __ bind(&return_undefined);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001867 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001868 __ ret((argc + 1) * kPointerSize);
1869
1870 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001871 __ TailCallExternalReference(
lrn@chromium.org7516f052011-03-30 08:52:27 +00001872 ExternalReference(Builtins::c_ArrayPop, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001873 argc + 1,
1874 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001875
ager@chromium.orgac091b72010-05-05 07:34:42 +00001876 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001877 GenerateMissBranch();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001878
1879 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001880 return GetCode(function);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001881}
1882
1883
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001884Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1885 Handle<Object> object,
1886 Handle<JSObject> holder,
1887 Handle<JSGlobalPropertyCell> cell,
1888 Handle<JSFunction> function,
1889 Handle<String> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001890 // ----------- S t a t e -------------
1891 // -- rcx : function name
1892 // -- rsp[0] : return address
1893 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1894 // -- ...
1895 // -- rsp[(argc + 1) * 8] : receiver
1896 // -----------------------------------
1897
1898 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001899 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001900
1901 const int argc = arguments().immediate();
1902
1903 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001904 Label name_miss;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001905 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001906 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001907 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001908 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001909 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001910 index_out_of_range_label = &miss;
1911 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001912 GenerateNameCheck(name, &name_miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001913
1914 // Check that the maps starting from the prototype haven't changed.
1915 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1916 Context::STRING_FUNCTION_INDEX,
1917 rax,
1918 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001919 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001920 CheckPrototypes(
1921 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
1922 rax, holder, rbx, rdx, rdi, name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001923
1924 Register receiver = rbx;
1925 Register index = rdi;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001926 Register result = rax;
1927 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
1928 if (argc > 0) {
1929 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
1930 } else {
1931 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1932 }
1933
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001934 StringCharCodeAtGenerator generator(receiver,
1935 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001936 result,
1937 &miss, // When not a string.
1938 &miss, // When not a number.
1939 index_out_of_range_label,
1940 STRING_INDEX_IS_NUMBER);
1941 generator.GenerateFast(masm());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001942 __ ret((argc + 1) * kPointerSize);
1943
1944 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001945 generator.GenerateSlow(masm(), call_helper);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001946
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001947 if (index_out_of_range.is_linked()) {
1948 __ bind(&index_out_of_range);
1949 __ LoadRoot(rax, Heap::kNanValueRootIndex);
1950 __ ret((argc + 1) * kPointerSize);
1951 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001952
1953 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001954 // Restore function name in rcx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001955 __ Move(rcx, name);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001956 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001957 GenerateMissBranch();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001958
1959 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001960 return GetCode(function);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001961}
1962
1963
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001964Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1965 Handle<Object> object,
1966 Handle<JSObject> holder,
1967 Handle<JSGlobalPropertyCell> cell,
1968 Handle<JSFunction> function,
1969 Handle<String> name) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001970 // ----------- S t a t e -------------
1971 // -- rcx : function name
1972 // -- rsp[0] : return address
1973 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1974 // -- ...
1975 // -- rsp[(argc + 1) * 8] : receiver
1976 // -----------------------------------
1977
1978 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001979 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001980
1981 const int argc = arguments().immediate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001982 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001983 Label name_miss;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001984 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001985 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001986 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001987 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001988 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001989 index_out_of_range_label = &miss;
1990 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001991 GenerateNameCheck(name, &name_miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001992
1993 // Check that the maps starting from the prototype haven't changed.
1994 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1995 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001996 rax,
1997 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001998 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001999 CheckPrototypes(
2000 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2001 rax, holder, rbx, rdx, rdi, name, &miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002002
2003 Register receiver = rax;
2004 Register index = rdi;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002005 Register scratch = rdx;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002006 Register result = rax;
2007 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
2008 if (argc > 0) {
2009 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
2010 } else {
2011 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2012 }
2013
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002014 StringCharAtGenerator generator(receiver,
2015 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002016 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002017 result,
2018 &miss, // When not a string.
2019 &miss, // When not a number.
2020 index_out_of_range_label,
2021 STRING_INDEX_IS_NUMBER);
2022 generator.GenerateFast(masm());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002023 __ ret((argc + 1) * kPointerSize);
2024
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002025 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002026 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002027
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002028 if (index_out_of_range.is_linked()) {
2029 __ bind(&index_out_of_range);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002030 __ LoadRoot(rax, Heap::kempty_stringRootIndex);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002031 __ ret((argc + 1) * kPointerSize);
2032 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002033 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002034 // Restore function name in rcx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002035 __ Move(rcx, name);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002036 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002037 GenerateMissBranch();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002038
2039 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002040 return GetCode(function);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002041}
2042
2043
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002044Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2045 Handle<Object> object,
2046 Handle<JSObject> holder,
2047 Handle<JSGlobalPropertyCell> cell,
2048 Handle<JSFunction> function,
2049 Handle<String> name) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002050 // ----------- S t a t e -------------
2051 // -- rcx : function name
2052 // -- rsp[0] : return address
2053 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
2054 // -- ...
2055 // -- rsp[(argc + 1) * 8] : receiver
2056 // -----------------------------------
2057
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002058 // If the object is not a JSObject or we got an unexpected number of
2059 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002060 const int argc = arguments().immediate();
2061 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002062
2063 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002064 GenerateNameCheck(name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002065
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002066 if (cell.is_null()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002067 __ movq(rdx, Operand(rsp, 2 * kPointerSize));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002068 __ JumpIfSmi(rdx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002069 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
2070 name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002071 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002072 ASSERT(cell->value() == *function);
2073 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2074 &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002075 GenerateLoadFunctionFromCell(cell, function, &miss);
2076 }
2077
2078 // Load the char code argument.
2079 Register code = rbx;
2080 __ movq(code, Operand(rsp, 1 * kPointerSize));
2081
2082 // Check the code is a smi.
2083 Label slow;
2084 __ JumpIfNotSmi(code, &slow);
2085
2086 // Convert the smi code to uint16.
2087 __ SmiAndConstant(code, code, Smi::FromInt(0xffff));
2088
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002089 StringCharFromCodeGenerator generator(code, rax);
2090 generator.GenerateFast(masm());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002091 __ ret(2 * kPointerSize);
2092
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002093 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002094 generator.GenerateSlow(masm(), call_helper);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002095
2096 // Tail call the full function. We do not have to patch the receiver
2097 // because the function makes no use of it.
2098 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002099 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002100 ? CALL_AS_FUNCTION
2101 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002102 ParameterCount expected(function);
2103 __ InvokeFunction(function, expected, arguments(),
2104 JUMP_FUNCTION, NullCallWrapper(), call_kind);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002105
2106 __ bind(&miss);
2107 // rcx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002108 GenerateMissBranch();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002109
2110 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002111 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002112}
2113
2114
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002115Handle<Code> CallStubCompiler::CompileMathFloorCall(
2116 Handle<Object> object,
2117 Handle<JSObject> holder,
2118 Handle<JSGlobalPropertyCell> cell,
2119 Handle<JSFunction> function,
2120 Handle<String> name) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002121 // TODO(872): implement this.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002122 return Handle<Code>::null();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002123}
2124
2125
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002126Handle<Code> CallStubCompiler::CompileMathAbsCall(
2127 Handle<Object> object,
2128 Handle<JSObject> holder,
2129 Handle<JSGlobalPropertyCell> cell,
2130 Handle<JSFunction> function,
2131 Handle<String> name) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002132 // ----------- S t a t e -------------
2133 // -- rcx : function name
2134 // -- rsp[0] : return address
2135 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
2136 // -- ...
2137 // -- rsp[(argc + 1) * 8] : receiver
2138 // -----------------------------------
2139
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002140 // If the object is not a JSObject or we got an unexpected number of
2141 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002142 const int argc = arguments().immediate();
2143 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002144
2145 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002146 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002147
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002148 if (cell.is_null()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002149 __ movq(rdx, Operand(rsp, 2 * kPointerSize));
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002150 __ JumpIfSmi(rdx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002151 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
2152 name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002153 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002154 ASSERT(cell->value() == *function);
2155 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2156 &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002157 GenerateLoadFunctionFromCell(cell, function, &miss);
2158 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002159 // Load the (only) argument into rax.
2160 __ movq(rax, Operand(rsp, 1 * kPointerSize));
2161
2162 // Check if the argument is a smi.
2163 Label not_smi;
2164 STATIC_ASSERT(kSmiTag == 0);
2165 __ JumpIfNotSmi(rax, &not_smi);
2166 __ SmiToInteger32(rax, rax);
2167
2168 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2169 // otherwise.
2170 __ movl(rbx, rax);
2171 __ sarl(rbx, Immediate(kBitsPerInt - 1));
2172
2173 // Do bitwise not or do nothing depending on ebx.
2174 __ xorl(rax, rbx);
2175
2176 // Add 1 or do nothing depending on ebx.
2177 __ subl(rax, rbx);
2178
2179 // If the result is still negative, go to the slow case.
2180 // This only happens for the most negative smi.
2181 Label slow;
2182 __ j(negative, &slow);
2183
2184 // Smi case done.
2185 __ Integer32ToSmi(rax, rax);
2186 __ ret(2 * kPointerSize);
2187
2188 // Check if the argument is a heap number and load its value.
2189 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002190 __ CheckMap(rax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002191 __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
2192
2193 // Check the sign of the argument. If the argument is positive,
2194 // just return it.
2195 Label negative_sign;
2196 const int sign_mask_shift =
2197 (HeapNumber::kExponentOffset - HeapNumber::kValueOffset) * kBitsPerByte;
2198 __ movq(rdi, static_cast<int64_t>(HeapNumber::kSignMask) << sign_mask_shift,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00002199 RelocInfo::NONE64);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002200 __ testq(rbx, rdi);
2201 __ j(not_zero, &negative_sign);
2202 __ ret(2 * kPointerSize);
2203
2204 // If the argument is negative, clear the sign, and return a new
2205 // number. We still have the sign mask in rdi.
2206 __ bind(&negative_sign);
2207 __ xor_(rbx, rdi);
2208 __ AllocateHeapNumber(rax, rdx, &slow);
2209 __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rbx);
2210 __ ret(2 * kPointerSize);
2211
2212 // Tail call the full function. We do not have to patch the receiver
2213 // because the function makes no use of it.
2214 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002215 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002216 ? CALL_AS_FUNCTION
2217 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002218 ParameterCount expected(function);
2219 __ InvokeFunction(function, expected, arguments(),
2220 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002221
2222 __ bind(&miss);
2223 // rcx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002224 GenerateMissBranch();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002225
2226 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002227 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002228}
2229
2230
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002231Handle<Code> CallStubCompiler::CompileFastApiCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002232 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002233 Handle<Object> object,
2234 Handle<JSObject> holder,
2235 Handle<JSGlobalPropertyCell> cell,
2236 Handle<JSFunction> function,
2237 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002238 ASSERT(optimization.is_simple_api_call());
2239 // Bail out if object is a global object as we don't want to
2240 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002241 if (object->IsGlobalObject()) return Handle<Code>::null();
2242 if (!cell.is_null()) return Handle<Code>::null();
2243 if (!object->IsJSObject()) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002244 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002245 Handle<JSObject>::cast(object), holder);
2246 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002247
2248 Label miss, miss_before_stack_reserved;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002249 GenerateNameCheck(name, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002250
2251 // Get the receiver from the stack.
2252 const int argc = arguments().immediate();
2253 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2254
2255 // Check that the receiver isn't a smi.
2256 __ JumpIfSmi(rdx, &miss_before_stack_reserved);
2257
lrn@chromium.org7516f052011-03-30 08:52:27 +00002258 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002259 __ IncrementCounter(counters->call_const(), 1);
2260 __ IncrementCounter(counters->call_const_fast_api(), 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002261
2262 // Allocate space for v8::Arguments implicit values. Must be initialized
2263 // before calling any runtime function.
2264 __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2265
2266 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002267 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
2268 name, depth, &miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002269
2270 // Move the return address on top of the stack.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002271 __ movq(rax, Operand(rsp, 4 * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002272 __ movq(Operand(rsp, 0 * kPointerSize), rax);
2273
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002274 GenerateFastApiCall(masm(), optimization, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002275
2276 __ bind(&miss);
2277 __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2278
2279 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002280 GenerateMissBranch();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002281
2282 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002283 return GetCode(function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002284}
2285
2286
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002287void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2288 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002289 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002290 CheckType check,
2291 Label* success) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002292 // ----------- S t a t e -------------
2293 // rcx : function name
2294 // rsp[0] : return address
2295 // rsp[8] : argument argc
2296 // rsp[16] : argument argc - 1
2297 // ...
2298 // rsp[argc * 8] : argument 1
2299 // rsp[(argc + 1) * 8] : argument 0 = receiver
2300 // -----------------------------------
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002301 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002302 GenerateNameCheck(name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002303
2304 // Get the receiver from the stack.
2305 const int argc = arguments().immediate();
2306 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2307
2308 // Check that the receiver isn't a smi.
2309 if (check != NUMBER_CHECK) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002310 __ JumpIfSmi(rdx, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002311 }
2312
2313 // Make sure that it's okay not to patch the on stack receiver
2314 // unless we're doing a receiver map check.
2315 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2316
lrn@chromium.org7516f052011-03-30 08:52:27 +00002317 Counters* counters = isolate()->counters();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002318 switch (check) {
2319 case RECEIVER_MAP_CHECK:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002320 __ IncrementCounter(counters->call_const(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002321
2322 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002323 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax,
2324 rdi, name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002325
2326 // Patch the receiver on the stack with the global proxy if
2327 // necessary.
2328 if (object->IsGlobalObject()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002329 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
2330 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
2331 }
2332 break;
2333
2334 case STRING_CHECK:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002335 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002336 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
2337 __ j(above_equal, &miss);
2338 // Check that the maps starting from the prototype haven't changed.
2339 GenerateDirectLoadGlobalFunctionPrototype(
2340 masm(), Context::STRING_FUNCTION_INDEX, rax, &miss);
2341 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002342 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002343 rax, holder, rbx, rdx, rdi, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002344 break;
2345
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002346 case SYMBOL_CHECK:
2347 // Check that the object is a symbol.
2348 __ CmpObjectType(rdx, SYMBOL_TYPE, rax);
2349 __ j(not_equal, &miss);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002350 // Check that the maps starting from the prototype haven't changed.
2351 GenerateDirectLoadGlobalFunctionPrototype(
2352 masm(), Context::SYMBOL_FUNCTION_INDEX, rax, &miss);
2353 CheckPrototypes(
2354 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2355 rax, holder, rbx, rdx, rdi, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002356 break;
2357
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002358 case NUMBER_CHECK: {
2359 Label fast;
2360 // Check that the object is a smi or a heap number.
2361 __ JumpIfSmi(rdx, &fast);
2362 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax);
2363 __ j(not_equal, &miss);
2364 __ bind(&fast);
2365 // Check that the maps starting from the prototype haven't changed.
2366 GenerateDirectLoadGlobalFunctionPrototype(
2367 masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss);
2368 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002369 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002370 rax, holder, rbx, rdx, rdi, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002371 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002372 }
2373 case BOOLEAN_CHECK: {
2374 Label fast;
2375 // Check that the object is a boolean.
2376 __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
2377 __ j(equal, &fast);
2378 __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
2379 __ j(not_equal, &miss);
2380 __ bind(&fast);
2381 // Check that the maps starting from the prototype haven't changed.
2382 GenerateDirectLoadGlobalFunctionPrototype(
2383 masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
2384 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002385 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002386 rax, holder, rbx, rdx, rdi, name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002387 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002388 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002389 }
2390
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002391 __ jmp(success);
2392
2393 // Handle call cache miss.
2394 __ bind(&miss);
2395 GenerateMissBranch();
2396}
2397
2398
2399void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002400 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002401 ? CALL_AS_FUNCTION
2402 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002403 ParameterCount expected(function);
2404 __ InvokeFunction(function, expected, arguments(),
2405 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002406}
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002407
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002408
2409Handle<Code> CallStubCompiler::CompileCallConstant(
2410 Handle<Object> object,
2411 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002412 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002413 CheckType check,
2414 Handle<JSFunction> function) {
2415 if (HasCustomCallGenerator(function)) {
2416 Handle<Code> code = CompileCustomCall(object, holder,
2417 Handle<JSGlobalPropertyCell>::null(),
ulan@chromium.org750145a2013-03-07 15:14:13 +00002418 function, Handle<String>::cast(name));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002419 // A null handle means bail out to the regular compiler code below.
2420 if (!code.is_null()) return code;
2421 }
2422
2423 Label success;
2424
2425 CompileHandlerFrontend(object, holder, name, check, &success);
2426 __ bind(&success);
2427 CompileHandlerBackend(function);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002428
2429 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002430 return GetCode(function);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002431}
2432
2433
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002434Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2435 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002436 Handle<Name> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002437 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00002438 // rcx : function name
2439 // rsp[0] : return address
2440 // rsp[8] : argument argc
2441 // rsp[16] : argument argc - 1
2442 // ...
2443 // rsp[argc * 8] : argument 1
2444 // rsp[(argc + 1) * 8] : argument 0 = receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002445 // -----------------------------------
2446 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002447 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002448
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002449 // Get the number of arguments.
2450 const int argc = arguments().immediate();
2451
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002452 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002453 LookupPostInterceptor(holder, name, &lookup);
2454
2455 // Get the receiver from the stack.
2456 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2457
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002458 CallInterceptorCompiler compiler(this, arguments(), rcx, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002459 compiler.Compile(masm(), object, holder, name, &lookup, rdx, rbx, rdi, rax,
2460 &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002461
2462 // Restore receiver.
2463 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2464
2465 // Check that the function really is a function.
ager@chromium.org4af710e2009-09-15 12:20:11 +00002466 __ JumpIfSmi(rax, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002467 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2468 __ j(not_equal, &miss);
2469
2470 // Patch the receiver on the stack with the global proxy if
2471 // necessary.
2472 if (object->IsGlobalObject()) {
2473 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
2474 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
2475 }
2476
2477 // Invoke the function.
2478 __ movq(rdi, rax);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002479 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002480 ? CALL_AS_FUNCTION
2481 : CALL_AS_METHOD;
2482 __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
2483 NullCallWrapper(), call_kind);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002484
2485 // Handle load cache miss.
2486 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002487 GenerateMissBranch();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002488
2489 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002490 return GetCode(Code::INTERCEPTOR, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002491}
2492
2493
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002494Handle<Code> CallStubCompiler::CompileCallGlobal(
2495 Handle<JSObject> object,
2496 Handle<GlobalObject> holder,
2497 Handle<JSGlobalPropertyCell> cell,
2498 Handle<JSFunction> function,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002499 Handle<Name> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002500 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00002501 // rcx : function name
2502 // rsp[0] : return address
2503 // rsp[8] : argument argc
2504 // rsp[16] : argument argc - 1
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002505 // ...
ager@chromium.org5c838252010-02-19 08:53:10 +00002506 // rsp[argc * 8] : argument 1
2507 // rsp[(argc + 1) * 8] : argument 0 = receiver
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002508 // -----------------------------------
2509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002510 if (HasCustomCallGenerator(function)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002511 Handle<Code> code = CompileCustomCall(
2512 object, holder, cell, function, Handle<String>::cast(name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002513 // A null handle means bail out to the regular compiler code below.
2514 if (!code.is_null()) return code;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002515 }
2516
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002517 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002518 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002519
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002520 // Get the number of arguments.
2521 const int argc = arguments().immediate();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002522 GenerateGlobalReceiverCheck(object, holder, name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002523 GenerateLoadFunctionFromCell(cell, function, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002524
2525 // Patch the receiver on the stack with the global proxy.
2526 if (object->IsGlobalObject()) {
2527 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
2528 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
2529 }
2530
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002531 // Set up the context (function already in rdi).
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002532 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
2533
2534 // Jump to the cached code (tail call).
lrn@chromium.org7516f052011-03-30 08:52:27 +00002535 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002536 __ IncrementCounter(counters->call_global_inline(), 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002537 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002538 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002539 ? CALL_AS_FUNCTION
2540 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002541 // We call indirectly through the code field in the function to
2542 // allow recompilation to take effect without changing any of the
2543 // call sites.
2544 __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
2545 __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION,
2546 NullCallWrapper(), call_kind);
2547
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002548 // Handle call cache miss.
2549 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002550 __ IncrementCounter(counters->call_global_inline_miss(), 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002551 GenerateMissBranch();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002552
2553 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002554 return GetCode(Code::NORMAL, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002555}
2556
2557
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002558Handle<Code> StoreStubCompiler::CompileStoreCallback(
ulan@chromium.org750145a2013-03-07 15:14:13 +00002559 Handle<Name> name,
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002560 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002561 Handle<JSObject> holder,
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002562 Handle<ExecutableAccessorInfo> callback) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002563 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002564 // Check that the maps haven't changed.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002565 __ JumpIfSmi(receiver(), &miss);
2566 CheckPrototypes(object, receiver(), holder,
2567 scratch1(), scratch2(), scratch3(), name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002568
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002569 // Stub never generated for non-global objects that require access checks.
2570 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002571
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002572 __ pop(scratch1()); // remove the return address
2573 __ push(receiver());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002574 __ Push(callback); // callback info
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002575 __ push(this->name());
2576 __ push(value());
2577 __ push(scratch1()); // restore return address
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002578
2579 // Do tail-call to the runtime system.
2580 ExternalReference store_callback_property =
lrn@chromium.org7516f052011-03-30 08:52:27 +00002581 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002582 __ TailCallExternalReference(store_callback_property, 4, 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002583
2584 // Handle store cache miss.
2585 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002586 TailCallBuiltin(masm(), MissBuiltin(kind()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002587
2588 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002589 return GetICCode(kind(), Code::CALLBACKS, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002590}
2591
2592
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002593#undef __
2594#define __ ACCESS_MASM(masm)
2595
2596
2597void StoreStubCompiler::GenerateStoreViaSetter(
2598 MacroAssembler* masm,
2599 Handle<JSFunction> setter) {
2600 // ----------- S t a t e -------------
2601 // -- rax : value
2602 // -- rcx : name
2603 // -- rdx : receiver
2604 // -- rsp[0] : return address
2605 // -----------------------------------
2606 {
2607 FrameScope scope(masm, StackFrame::INTERNAL);
2608
2609 // Save value register, so we can restore it later.
2610 __ push(rax);
2611
2612 if (!setter.is_null()) {
2613 // Call the JavaScript setter with receiver and value on the stack.
2614 __ push(rdx);
2615 __ push(rax);
2616 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002617 ParameterCount expected(setter);
2618 __ InvokeFunction(setter, expected, actual,
2619 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002620 } else {
2621 // If we generate a global code snippet for deoptimization only, remember
2622 // the place to continue after deoptimization.
2623 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2624 }
2625
2626 // We have to return the passed value, not the return value of the setter.
2627 __ pop(rax);
2628
2629 // Restore context register.
2630 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2631 }
2632 __ ret(0);
2633}
2634
2635
2636#undef __
2637#define __ ACCESS_MASM(masm())
2638
2639
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002640Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002641 Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002642 Handle<Name> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002643 Label miss;
2644
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002645 // Check that the map of the object hasn't changed.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002646 __ CheckMap(receiver(), Handle<Map>(object->map()), &miss,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002647 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002648
2649 // Perform global security token check if needed.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002650 if (object->IsJSGlobalProxy()) {
2651 __ CheckAccessGlobalProxy(receiver(), scratch1(), &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002652 }
2653
2654 // Stub never generated for non-global objects that require access
2655 // checks.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002656 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002657
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002658 __ pop(scratch1()); // remove the return address
2659 __ push(receiver());
2660 __ push(this->name());
2661 __ push(value());
2662 __ Push(Smi::FromInt(strict_mode()));
2663 __ push(scratch1()); // restore return address
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002664
2665 // Do tail-call to the runtime system.
2666 ExternalReference store_ic_property =
lrn@chromium.org7516f052011-03-30 08:52:27 +00002667 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002668 __ TailCallExternalReference(store_ic_property, 4, 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002669
2670 // Handle store cache miss.
2671 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002672 TailCallBuiltin(masm(), MissBuiltin(kind()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002673
2674 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002675 return GetICCode(kind(), Code::INTERCEPTOR, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002676}
2677
2678
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002679Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2680 Handle<GlobalObject> object,
2681 Handle<JSGlobalPropertyCell> cell,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002682 Handle<Name> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002683 Label miss;
2684
2685 // Check that the map of the global has not changed.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002686 __ Cmp(FieldOperand(receiver(), HeapObject::kMapOffset),
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002687 Handle<Map>(object->map()));
2688 __ j(not_equal, &miss);
2689
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002690 // Compute the cell operand to use.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002691 __ Move(scratch1(), cell);
2692 Operand cell_operand =
2693 FieldOperand(scratch1(), JSGlobalPropertyCell::kValueOffset);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002694
ager@chromium.org378b34e2011-01-28 08:04:38 +00002695 // Check that the value in the cell is not the hole. If it is, this
2696 // cell could have been deleted and reintroducing the global needs
2697 // to update the property details in the property dictionary of the
2698 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002699 __ CompareRoot(cell_operand, Heap::kTheHoleValueRootIndex);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002700 __ j(equal, &miss);
2701
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002702 // Store the value in the cell.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002703 __ movq(cell_operand, value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002704 // Cells are always rescanned, so no write barrier here.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002705
2706 // Return the value (register rax).
lrn@chromium.org7516f052011-03-30 08:52:27 +00002707 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002708 __ IncrementCounter(counters->named_store_global_inline(), 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002709 __ ret(0);
2710
2711 // Handle store cache miss.
2712 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002713 __ IncrementCounter(counters->named_store_global_inline_miss(), 1);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002714 TailCallBuiltin(masm(), MissBuiltin(kind()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002715
2716 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002717 return GetICCode(kind(), Code::NORMAL, name);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002718}
2719
2720
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002721Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2722 MapHandleList* receiver_maps,
2723 CodeHandleList* handler_stubs,
2724 MapHandleList* transitioned_maps) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002725 Label miss;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002726 __ JumpIfSmi(receiver(), &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002727
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002728 __ movq(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002729 int receiver_count = receiver_maps->length();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002730 for (int i = 0; i < receiver_count; ++i) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002731 // Check map and tail call if there's a match
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002732 __ Cmp(scratch1(), receiver_maps->at(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002733 if (transitioned_maps->at(i).is_null()) {
2734 __ j(equal, handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002735 } else {
2736 Label next_map;
2737 __ j(not_equal, &next_map, Label::kNear);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002738 __ movq(transition_map(),
2739 transitioned_maps->at(i),
2740 RelocInfo::EMBEDDED_OBJECT);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002741 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002742 __ bind(&next_map);
2743 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002744 }
2745
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002746 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002747
2748 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002749
2750 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002751 return GetICCode(
2752 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002753}
2754
2755
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002756Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002757 Handle<JSObject> object,
2758 Handle<JSObject> last,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002759 Handle<Name> name,
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002760 Handle<GlobalObject> global) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002761 Label success;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002762
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002763 NonexistentHandlerFrontend(object, last, name, &success, global);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002764
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002765 __ bind(&success);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002766 // Return undefined if maps of the full prototype chain are still the
2767 // same and no global property with this name contains a value.
2768 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2769 __ ret(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002770
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002771 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00002772 return GetCode(kind(), Code::NONEXISTENT, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002773}
2774
2775
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002776Register* LoadStubCompiler::registers() {
2777 // receiver, name, scratch1, scratch2, scratch3, scratch4.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002778 static Register registers[] = { rax, rcx, rdx, rbx, rdi, r8 };
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002779 return registers;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002780}
2781
2782
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002783Register* KeyedLoadStubCompiler::registers() {
2784 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2785 static Register registers[] = { rdx, rax, rbx, rcx, rdi, r8 };
2786 return registers;
2787}
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002788
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002789
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002790Register* StoreStubCompiler::registers() {
2791 // receiver, name, value, scratch1, scratch2, scratch3.
2792 static Register registers[] = { rdx, rcx, rax, rbx, rdi, r8 };
2793 return registers;
2794}
2795
2796
2797Register* KeyedStoreStubCompiler::registers() {
2798 // receiver, name, value, scratch1, scratch2, scratch3.
2799 static Register registers[] = { rdx, rcx, rax, rbx, rdi, r8 };
2800 return registers;
2801}
2802
2803
ulan@chromium.org750145a2013-03-07 15:14:13 +00002804void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002805 Register name_reg,
2806 Label* miss) {
2807 __ Cmp(name_reg, name);
2808 __ j(not_equal, miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002809}
2810
2811
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002812void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
2813 Register name_reg,
2814 Label* miss) {
2815 __ Cmp(name_reg, name);
2816 __ j(not_equal, miss);
2817}
2818
2819
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002820#undef __
2821#define __ ACCESS_MASM(masm)
2822
2823
2824void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2825 Handle<JSFunction> getter) {
2826 // ----------- S t a t e -------------
2827 // -- rax : receiver
2828 // -- rcx : name
2829 // -- rsp[0] : return address
2830 // -----------------------------------
2831 {
2832 FrameScope scope(masm, StackFrame::INTERNAL);
2833
2834 if (!getter.is_null()) {
2835 // Call the JavaScript getter with the receiver on the stack.
2836 __ push(rax);
2837 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002838 ParameterCount expected(getter);
2839 __ InvokeFunction(getter, expected, actual,
2840 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002841 } else {
2842 // If we generate a global code snippet for deoptimization only, remember
2843 // the place to continue after deoptimization.
2844 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2845 }
2846
2847 // Restore context register.
2848 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2849 }
2850 __ ret(0);
2851}
2852
2853
2854#undef __
2855#define __ ACCESS_MASM(masm())
2856
2857
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002858Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2859 Handle<JSObject> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002860 Handle<GlobalObject> global,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002861 Handle<JSGlobalPropertyCell> cell,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002862 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002863 bool is_dont_delete) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002864 Label success, miss;
2865 // TODO(verwaest): Directly store to rax. Currently we cannot do this, since
2866 // rax is used as receiver(), which we would otherwise clobber before a
2867 // potential miss.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002868
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002869 __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
2870 HandlerFrontendHeader(
2871 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002872
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002873 // Get the value from the cell.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002874 __ Move(rbx, cell);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002875 __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset));
whesse@chromium.orge90029b2010-08-02 11:52:17 +00002876
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002877 // Check for deleted property if property can actually be deleted.
2878 if (!is_dont_delete) {
2879 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
2880 __ j(equal, &miss);
2881 } else if (FLAG_debug_code) {
2882 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
2883 __ Check(not_equal, "DontDelete cells can't contain the hole");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002884 }
2885
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002886 HandlerFrontendFooter(&success, &miss);
2887 __ bind(&success);
2888
lrn@chromium.org7516f052011-03-30 08:52:27 +00002889 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002890 __ IncrementCounter(counters->named_load_global_stub(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002891 __ movq(rax, rbx);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002892 __ ret(0);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002893
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002894 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00002895 return GetICCode(kind(), Code::NORMAL, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002896}
2897
2898
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002899Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002900 MapHandleList* receiver_maps,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002901 CodeHandleList* handlers,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002902 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002903 Code::StubType type,
2904 IcCheckType check) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002905 Label miss;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002906
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002907 if (check == PROPERTY) {
2908 GenerateNameCheck(name, this->name(), &miss);
2909 }
2910
2911 __ JumpIfSmi(receiver(), &miss);
2912 Register map_reg = scratch1();
2913 __ movq(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002914 int receiver_count = receiver_maps->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00002915 int number_of_handled_maps = 0;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002916 for (int current = 0; current < receiver_count; ++current) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00002917 Handle<Map> map = receiver_maps->at(current);
2918 if (!map->is_deprecated()) {
2919 number_of_handled_maps++;
2920 // Check map and tail call if there's a match
2921 __ Cmp(map_reg, receiver_maps->at(current));
2922 __ j(equal, handlers->at(current), RelocInfo::CODE_TARGET);
2923 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002924 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002925 ASSERT(number_of_handled_maps > 0);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002926
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002927 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002928 TailCallBuiltin(masm(), MissBuiltin(kind()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002929
2930 // Return the generated code.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002931 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00002932 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
ulan@chromium.org750145a2013-03-07 15:14:13 +00002933 return GetICCode(kind(), type, name, state);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002934}
2935
2936
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002937// Specialized stub for constructing objects from functions which only have only
2938// simple assignments of the form this.x = ...; in their body.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002939Handle<Code> ConstructStubCompiler::CompileConstructStub(
2940 Handle<JSFunction> function) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002941 // ----------- S t a t e -------------
2942 // -- rax : argc
2943 // -- rdi : constructor
2944 // -- rsp[0] : return address
2945 // -- rsp[4] : last argument
2946 // -----------------------------------
2947 Label generic_stub_call;
2948
2949 // Use r8 for holding undefined which is used in several places below.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002950 __ Move(r8, factory()->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002951
2952#ifdef ENABLE_DEBUGGER_SUPPORT
2953 // Check to see whether there are any break points in the function code. If
2954 // there are jump to the generic constructor stub which calls the actual
2955 // code for the function thereby hitting the break points.
2956 __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
2957 __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kDebugInfoOffset));
2958 __ cmpq(rbx, r8);
2959 __ j(not_equal, &generic_stub_call);
2960#endif
2961
2962 // Load the initial map and verify that it is in fact a map.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002963 // rdi: constructor
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002964 __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
2965 // Will both indicate a NULL and a Smi.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002966 STATIC_ASSERT(kSmiTag == 0);
ager@chromium.org4af710e2009-09-15 12:20:11 +00002967 __ JumpIfSmi(rbx, &generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002968 __ CmpObjectType(rbx, MAP_TYPE, rcx);
2969 __ j(not_equal, &generic_stub_call);
2970
2971#ifdef DEBUG
2972 // Cannot construct functions this way.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002973 // rbx: initial map
2974 __ CmpInstanceType(rbx, JS_FUNCTION_TYPE);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002975 __ Check(not_equal, "Function constructed by construct stub.");
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002976#endif
2977
2978 // Now allocate the JSObject in new space.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002979 // rbx: initial map
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002980 ASSERT(function->has_initial_map());
2981 int instance_size = function->initial_map()->instance_size();
2982#ifdef DEBUG
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002983 __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset));
2984 __ shl(rcx, Immediate(kPointerSizeLog2));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002985 __ cmpq(rcx, Immediate(instance_size));
2986 __ Check(equal, "Instance size of initial map changed.");
2987#endif
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002988 __ Allocate(instance_size, rdx, rcx, no_reg, &generic_stub_call,
2989 NO_ALLOCATION_FLAGS);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002990
2991 // Allocated the JSObject, now initialize the fields and add the heap tag.
2992 // rbx: initial map
2993 // rdx: JSObject (untagged)
2994 __ movq(Operand(rdx, JSObject::kMapOffset), rbx);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002995 __ Move(rbx, factory()->empty_fixed_array());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002996 __ movq(Operand(rdx, JSObject::kPropertiesOffset), rbx);
2997 __ movq(Operand(rdx, JSObject::kElementsOffset), rbx);
2998
2999 // rax: argc
3000 // rdx: JSObject (untagged)
3001 // Load the address of the first in-object property into r9.
3002 __ lea(r9, Operand(rdx, JSObject::kHeaderSize));
3003 // Calculate the location of the first argument. The stack contains only the
3004 // return address on top of the argc arguments.
3005 __ lea(rcx, Operand(rsp, rax, times_pointer_size, 0));
3006
3007 // rax: argc
3008 // rcx: first argument
3009 // rdx: JSObject (untagged)
3010 // r8: undefined
3011 // r9: first in-object property of the JSObject
3012 // Fill the initialized properties with a constant value or a passed argument
3013 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003014 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003015 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3016 if (shared->IsThisPropertyAssignmentArgument(i)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003017 // Check if the argument assigned to the property is actually passed.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003018 // If argument is not passed the property is set to undefined,
3019 // otherwise find it on the stack.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003020 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003021 __ movq(rbx, r8);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003022 __ cmpq(rax, Immediate(arg_number));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003023 __ cmovq(above, rbx, Operand(rcx, arg_number * -kPointerSize));
3024 // Store value in the property.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003025 __ movq(Operand(r9, i * kPointerSize), rbx);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003026 } else {
3027 // Set the property to the constant value.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003028 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i),
3029 isolate());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003030 __ Move(Operand(r9, i * kPointerSize), constant);
3031 }
3032 }
3033
3034 // Fill the unused in-object property fields with undefined.
3035 for (int i = shared->this_property_assignments_count();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00003036 i < function->initial_map()->inobject_properties();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003037 i++) {
3038 __ movq(Operand(r9, i * kPointerSize), r8);
3039 }
3040
3041 // rax: argc
3042 // rdx: JSObject (untagged)
3043 // Move argc to rbx and the JSObject to return to rax and tag it.
3044 __ movq(rbx, rax);
3045 __ movq(rax, rdx);
3046 __ or_(rax, Immediate(kHeapObjectTag));
3047
3048 // rax: JSObject
3049 // rbx: argc
3050 // Remove caller arguments and receiver from the stack and return.
3051 __ pop(rcx);
3052 __ lea(rsp, Operand(rsp, rbx, times_pointer_size, 1 * kPointerSize));
3053 __ push(rcx);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003054 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003055 __ IncrementCounter(counters->constructed_objects(), 1);
3056 __ IncrementCounter(counters->constructed_objects_stub(), 1);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003057 __ ret(0);
3058
3059 // Jump to the generic stub in case the specialized code cannot handle the
3060 // construction.
3061 __ bind(&generic_stub_call);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003062 Handle<Code> code = isolate()->builtins()->JSConstructStubGeneric();
3063 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003064
3065 // Return the generated code.
3066 return GetCode();
3067}
3068
3069
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003070#undef __
3071#define __ ACCESS_MASM(masm)
3072
3073
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003074void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3075 MacroAssembler* masm) {
3076 // ----------- S t a t e -------------
3077 // -- rax : key
3078 // -- rdx : receiver
3079 // -- rsp[0] : return address
3080 // -----------------------------------
3081 Label slow, miss_force_generic;
3082
3083 // This stub is meant to be tail-jumped to, the receiver must already
3084 // have been verified by the caller to not be a smi.
3085
3086 __ JumpIfNotSmi(rax, &miss_force_generic);
3087 __ SmiToInteger32(rbx, rax);
3088 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
3089
3090 // Check whether the elements is a number dictionary.
3091 // rdx: receiver
3092 // rax: key
3093 // rbx: key as untagged int32
3094 // rcx: elements
3095 __ LoadFromNumberDictionary(&slow, rcx, rax, rbx, r9, rdi, rax);
3096 __ ret(0);
3097
3098 __ bind(&slow);
3099 // ----------- S t a t e -------------
3100 // -- rax : key
3101 // -- rdx : receiver
3102 // -- rsp[0] : return address
3103 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003104 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003105
3106 __ bind(&miss_force_generic);
3107 // ----------- S t a t e -------------
3108 // -- rax : key
3109 // -- rdx : receiver
3110 // -- rsp[0] : return address
3111 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003112 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003113}
3114
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003115
3116static void GenerateSmiKeyCheck(MacroAssembler* masm,
3117 Register key,
3118 Register scratch,
3119 XMMRegister xmm_scratch0,
3120 XMMRegister xmm_scratch1,
3121 Label* fail) {
3122 // Check that key is a smi or a heap number containing a smi and branch
3123 // if the check fails.
3124 Label key_ok;
3125 __ JumpIfSmi(key, &key_ok);
3126 __ CheckMap(key,
3127 masm->isolate()->factory()->heap_number_map(),
3128 fail,
3129 DONT_DO_SMI_CHECK);
3130 __ movsd(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset));
3131 __ cvttsd2si(scratch, xmm_scratch0);
3132 __ cvtlsi2sd(xmm_scratch1, scratch);
3133 __ ucomisd(xmm_scratch1, xmm_scratch0);
3134 __ j(not_equal, fail);
3135 __ j(parity_even, fail); // NaN.
3136 __ Integer32ToSmi(key, scratch);
3137 __ bind(&key_ok);
3138}
3139
3140
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003141void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3142 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003143 ElementsKind elements_kind) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003144 // ----------- S t a t e -------------
3145 // -- rax : value
3146 // -- rcx : key
3147 // -- rdx : receiver
3148 // -- rsp[0] : return address
3149 // -----------------------------------
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003150 Label slow, miss_force_generic;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003151
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003152 // This stub is meant to be tail-jumped to, the receiver must already
3153 // have been verified by the caller to not be a smi.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003154
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003155 // Check that the key is a smi or a heap number convertible to a smi.
3156 GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003157
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003158 // Check that the index is in range.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003159 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
danno@chromium.orgb6451162011-08-17 14:33:23 +00003160 __ SmiToInteger32(rdi, rcx); // Untag the index.
3161 __ cmpq(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003162 // Unsigned comparison catches both negative and too-large values.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003163 __ j(above_equal, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003164
3165 // Handle both smis and HeapNumbers in the fast path. Go to the
3166 // runtime for all other kinds of values.
3167 // rax: value
3168 // rcx: key (a smi)
3169 // rdx: receiver (a JSObject)
3170 // rbx: elements array
danno@chromium.orgb6451162011-08-17 14:33:23 +00003171 // rdi: untagged key
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003172 Label check_heap_number;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003173 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003174 // Float to pixel conversion is only implemented in the runtime for now.
3175 __ JumpIfNotSmi(rax, &slow);
3176 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003177 __ JumpIfNotSmi(rax, &check_heap_number, Label::kNear);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003178 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003179 // No more branches to slow case on this path. Key and receiver not needed.
3180 __ SmiToInteger32(rdx, rax);
3181 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
3182 // rbx: base pointer of external storage
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003183 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003184 case EXTERNAL_PIXEL_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003185 { // Clamp the value to [0..255].
3186 Label done;
3187 __ testl(rdx, Immediate(0xFFFFFF00));
3188 __ j(zero, &done, Label::kNear);
3189 __ setcc(negative, rdx); // 1 if negative, 0 if positive.
3190 __ decb(rdx); // 0 if negative, 255 if positive.
3191 __ bind(&done);
3192 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003193 __ movb(Operand(rbx, rdi, times_1, 0), rdx);
3194 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003195 case EXTERNAL_BYTE_ELEMENTS:
3196 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003197 __ movb(Operand(rbx, rdi, times_1, 0), rdx);
3198 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003199 case EXTERNAL_SHORT_ELEMENTS:
3200 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003201 __ movw(Operand(rbx, rdi, times_2, 0), rdx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003202 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003203 case EXTERNAL_INT_ELEMENTS:
3204 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003205 __ movl(Operand(rbx, rdi, times_4, 0), rdx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003206 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003207 case EXTERNAL_FLOAT_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003208 // Need to perform int-to-float conversion.
3209 __ cvtlsi2ss(xmm0, rdx);
danno@chromium.orgb6451162011-08-17 14:33:23 +00003210 __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003211 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003212 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003213 // Need to perform int-to-float conversion.
3214 __ cvtlsi2sd(xmm0, rdx);
danno@chromium.orgb6451162011-08-17 14:33:23 +00003215 __ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003216 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003217 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003218 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003219 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003220 case FAST_HOLEY_ELEMENTS:
3221 case FAST_HOLEY_SMI_ELEMENTS:
3222 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003223 case DICTIONARY_ELEMENTS:
3224 case NON_STRICT_ARGUMENTS_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003225 UNREACHABLE();
3226 break;
3227 }
3228 __ ret(0);
3229
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003230 // TODO(danno): handle heap number -> pixel array conversion
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003231 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003232 __ bind(&check_heap_number);
3233 // rax: value
3234 // rcx: key (a smi)
3235 // rdx: receiver (a JSObject)
3236 // rbx: elements array
danno@chromium.orgb6451162011-08-17 14:33:23 +00003237 // rdi: untagged key
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003238 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister);
3239 __ j(not_equal, &slow);
3240 // No more branches to slow case on this path.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003241
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003242 // The WebGL specification leaves the behavior of storing NaN and
3243 // +/-Infinity into integer arrays basically undefined. For more
3244 // reproducible behavior, convert these to zero.
3245 __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
3246 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
danno@chromium.orgb6451162011-08-17 14:33:23 +00003247 // rdi: untagged index
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003248 // rbx: base pointer of external storage
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003249 // top of FPU stack: value
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003250 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003251 __ cvtsd2ss(xmm0, xmm0);
danno@chromium.orgb6451162011-08-17 14:33:23 +00003252 __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003253 __ ret(0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003254 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00003255 __ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003256 __ ret(0);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003257 } else {
3258 // Perform float-to-int conversion with truncation (round-to-zero)
3259 // behavior.
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003260 // Fast path: use machine instruction to convert to int64. If that
3261 // fails (out-of-range), go into the runtime.
3262 __ cvttsd2siq(r8, xmm0);
3263 __ Set(kScratchRegister, V8_UINT64_C(0x8000000000000000));
3264 __ cmpq(r8, kScratchRegister);
3265 __ j(equal, &slow);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003266
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003267 // rdx: value (converted to an untagged integer)
3268 // rdi: untagged index
3269 // rbx: base pointer of external storage
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003270 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003271 case EXTERNAL_BYTE_ELEMENTS:
3272 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003273 __ movb(Operand(rbx, rdi, times_1, 0), r8);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003274 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003275 case EXTERNAL_SHORT_ELEMENTS:
3276 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003277 __ movw(Operand(rbx, rdi, times_2, 0), r8);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003278 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003279 case EXTERNAL_INT_ELEMENTS:
3280 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003281 __ movl(Operand(rbx, rdi, times_4, 0), r8);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003282 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003283 case EXTERNAL_PIXEL_ELEMENTS:
3284 case EXTERNAL_FLOAT_ELEMENTS:
3285 case EXTERNAL_DOUBLE_ELEMENTS:
3286 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003287 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003288 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003289 case FAST_HOLEY_ELEMENTS:
3290 case FAST_HOLEY_SMI_ELEMENTS:
3291 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003292 case DICTIONARY_ELEMENTS:
3293 case NON_STRICT_ARGUMENTS_ELEMENTS:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003294 UNREACHABLE();
3295 break;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003296 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003297 __ ret(0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003298 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003299 }
3300
3301 // Slow case: call runtime.
3302 __ bind(&slow);
3303
3304 // ----------- S t a t e -------------
3305 // -- rax : value
3306 // -- rcx : key
3307 // -- rdx : receiver
3308 // -- rsp[0] : return address
3309 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003310 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003311
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003312 // Miss case: call runtime.
3313 __ bind(&miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003314
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003315 // ----------- S t a t e -------------
3316 // -- rax : value
3317 // -- rcx : key
3318 // -- rdx : receiver
3319 // -- rsp[0] : return address
3320 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003321 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003322}
3323
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003324
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003325void KeyedStoreStubCompiler::GenerateStoreFastElement(
3326 MacroAssembler* masm,
3327 bool is_js_array,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003328 ElementsKind elements_kind,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003329 KeyedAccessStoreMode store_mode) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003330 // ----------- S t a t e -------------
3331 // -- rax : value
3332 // -- rcx : key
3333 // -- rdx : receiver
3334 // -- rsp[0] : return address
3335 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003336 Label miss_force_generic, transition_elements_kind, finish_store, grow;
3337 Label check_capacity, slow;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003338
3339 // This stub is meant to be tail-jumped to, the receiver must already
3340 // have been verified by the caller to not be a smi.
3341
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003342 // Check that the key is a smi or a heap number convertible to a smi.
3343 GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003344
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003345 if (IsFastSmiElementsKind(elements_kind)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003346 __ JumpIfNotSmi(rax, &transition_elements_kind);
3347 }
3348
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003349 // Get the elements array and make sure it is a fast element array, not 'cow'.
3350 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003351 // Check that the key is within bounds.
3352 if (is_js_array) {
3353 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003354 if (IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003355 __ j(above_equal, &grow);
3356 } else {
3357 __ j(above_equal, &miss_force_generic);
3358 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003359 } else {
3360 __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
3361 __ j(above_equal, &miss_force_generic);
3362 }
3363
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003364 __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset),
3365 Heap::kFixedArrayMapRootIndex);
3366 __ j(not_equal, &miss_force_generic);
3367
3368 __ bind(&finish_store);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003369 if (IsFastSmiElementsKind(elements_kind)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003370 __ SmiToInteger32(rcx, rcx);
3371 __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize),
3372 rax);
3373 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003374 // Do the store and update the write barrier.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003375 ASSERT(IsFastObjectElementsKind(elements_kind));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003376 __ SmiToInteger32(rcx, rcx);
3377 __ lea(rcx,
3378 FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize));
3379 __ movq(Operand(rcx, 0), rax);
3380 // Make sure to preserve the value in register rax.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003381 __ movq(rbx, rax);
3382 __ RecordWrite(rdi, rcx, rbx, kDontSaveFPRegs);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003383 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003384
3385 // Done.
3386 __ ret(0);
3387
3388 // Handle store cache miss.
3389 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003390 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003391
3392 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003393 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003394
ulan@chromium.org750145a2013-03-07 15:14:13 +00003395 if (is_js_array && IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003396 // Grow the array by a single element if possible.
3397 __ bind(&grow);
3398
3399 // Make sure the array is only growing by a single element, anything else
3400 // must be handled by the runtime. Flags are already set by previous
3401 // compare.
3402 __ j(not_equal, &miss_force_generic);
3403
3404 // Check for the empty array, and preallocate a small backing store if
3405 // possible.
3406 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
3407 __ CompareRoot(rdi, Heap::kEmptyFixedArrayRootIndex);
3408 __ j(not_equal, &check_capacity);
3409
3410 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003411 __ Allocate(size, rdi, rbx, r8, &slow, TAG_OBJECT);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003412
3413 // rax: value
3414 // rcx: key
3415 // rdx: receiver
3416 // rdi: elements
3417 // Make sure that the backing store can hold additional elements.
3418 __ Move(FieldOperand(rdi, JSObject::kMapOffset),
3419 masm->isolate()->factory()->fixed_array_map());
3420 __ Move(FieldOperand(rdi, FixedArray::kLengthOffset),
3421 Smi::FromInt(JSArray::kPreallocatedArrayElements));
3422 __ LoadRoot(rbx, Heap::kTheHoleValueRootIndex);
3423 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3424 __ movq(FieldOperand(rdi, FixedArray::SizeFor(i)), rbx);
3425 }
3426
3427 // Store the element at index zero.
3428 __ movq(FieldOperand(rdi, FixedArray::SizeFor(0)), rax);
3429
3430 // Install the new backing store in the JSArray.
3431 __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi);
3432 __ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx,
3433 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3434
3435 // Increment the length of the array.
3436 __ Move(FieldOperand(rdx, JSArray::kLengthOffset), Smi::FromInt(1));
3437 __ ret(0);
3438
3439 __ bind(&check_capacity);
3440 // Check for cow elements, in general they are not handled by this stub.
3441 __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset),
3442 Heap::kFixedCOWArrayMapRootIndex);
3443 __ j(equal, &miss_force_generic);
3444
3445 // rax: value
3446 // rcx: key
3447 // rdx: receiver
3448 // rdi: elements
3449 // Make sure that the backing store can hold additional elements.
3450 __ cmpq(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
3451 __ j(above_equal, &slow);
3452
3453 // Grow the array and finish the store.
3454 __ SmiAddConstant(FieldOperand(rdx, JSArray::kLengthOffset),
3455 Smi::FromInt(1));
3456 __ jmp(&finish_store);
3457
3458 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003459 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003460 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003461}
3462
3463
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003464void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3465 MacroAssembler* masm,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003466 bool is_js_array,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003467 KeyedAccessStoreMode store_mode) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003468 // ----------- S t a t e -------------
3469 // -- rax : value
3470 // -- rcx : key
3471 // -- rdx : receiver
3472 // -- rsp[0] : return address
3473 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003474 Label miss_force_generic, transition_elements_kind, finish_store;
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003475 Label grow, slow, check_capacity, restore_key_transition_elements_kind;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003476
3477 // This stub is meant to be tail-jumped to, the receiver must already
3478 // have been verified by the caller to not be a smi.
3479
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003480 // Check that the key is a smi or a heap number convertible to a smi.
3481 GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003482
3483 // Get the elements array.
3484 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
3485 __ AssertFastElements(rdi);
3486
3487 // Check that the key is within bounds.
3488 if (is_js_array) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003489 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003490 if (IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003491 __ j(above_equal, &grow);
3492 } else {
3493 __ j(above_equal, &miss_force_generic);
3494 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003495 } else {
3496 __ SmiCompare(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003497 __ j(above_equal, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003498 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003499
3500 // Handle smi values specially
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003501 __ bind(&finish_store);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003502 __ SmiToInteger32(rcx, rcx);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003503 __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0,
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003504 &restore_key_transition_elements_kind);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003505 __ ret(0);
3506
3507 // Handle store cache miss, replacing the ic with the generic stub.
3508 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003509 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003510
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003511 __ bind(&restore_key_transition_elements_kind);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003512 // Restore smi-tagging of rcx.
3513 __ Integer32ToSmi(rcx, rcx);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003514 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003515 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003516
ulan@chromium.org750145a2013-03-07 15:14:13 +00003517 if (is_js_array && IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003518 // Grow the array by a single element if possible.
3519 __ bind(&grow);
3520
3521 // Make sure the array is only growing by a single element, anything else
3522 // must be handled by the runtime. Flags are already set by previous
3523 // compare.
3524 __ j(not_equal, &miss_force_generic);
3525
3526 // Transition on values that can't be stored in a FixedDoubleArray.
3527 Label value_is_smi;
3528 __ JumpIfSmi(rax, &value_is_smi);
3529 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
3530 Heap::kHeapNumberMapRootIndex);
3531 __ j(not_equal, &transition_elements_kind);
3532 __ bind(&value_is_smi);
3533
3534 // Check for the empty array, and preallocate a small backing store if
3535 // possible.
3536 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
3537 __ CompareRoot(rdi, Heap::kEmptyFixedArrayRootIndex);
3538 __ j(not_equal, &check_capacity);
3539
3540 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003541 __ Allocate(size, rdi, rbx, r8, &slow, TAG_OBJECT);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003542
3543 // rax: value
3544 // rcx: key
3545 // rdx: receiver
3546 // rdi: elements
3547 // Initialize the new FixedDoubleArray. Leave elements unitialized for
3548 // efficiency, they are guaranteed to be initialized before use.
3549 __ Move(FieldOperand(rdi, JSObject::kMapOffset),
3550 masm->isolate()->factory()->fixed_double_array_map());
3551 __ Move(FieldOperand(rdi, FixedDoubleArray::kLengthOffset),
3552 Smi::FromInt(JSArray::kPreallocatedArrayElements));
3553
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003554 // Increment the length of the array.
3555 __ SmiToInteger32(rcx, rcx);
3556 __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0,
3557 &restore_key_transition_elements_kind);
3558
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00003559 __ movq(r8, BitCast<int64_t, uint64_t>(kHoleNanInt64), RelocInfo::NONE64);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003560 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
3561 __ movq(FieldOperand(rdi, FixedDoubleArray::OffsetOfElementAt(i)), r8);
3562 }
3563
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003564 // Install the new backing store in the JSArray.
3565 __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi);
3566 __ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx,
3567 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3568
3569 // Increment the length of the array.
3570 __ Move(FieldOperand(rdx, JSArray::kLengthOffset), Smi::FromInt(1));
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003571 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003572 __ ret(0);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003573
3574 __ bind(&check_capacity);
3575 // rax: value
3576 // rcx: key
3577 // rdx: receiver
3578 // rdi: elements
3579 // Make sure that the backing store can hold additional elements.
3580 __ cmpq(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset));
3581 __ j(above_equal, &slow);
3582
3583 // Grow the array and finish the store.
3584 __ SmiAddConstant(FieldOperand(rdx, JSArray::kLengthOffset),
3585 Smi::FromInt(1));
3586 __ jmp(&finish_store);
3587
3588 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003589 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003590 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003591}
3592
3593
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003594#undef __
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003595
3596} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003597
3598#endif // V8_TARGET_ARCH_X64