blob: 5fdc2a1a7279fa256dda6a77a57f7bfe3ffa97ef [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.
113// Name must be a symbol 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,
117 Handle<String> name,
118 Register r0,
119 Register r1) {
120 ASSERT(name->IsSymbol());
121 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;
149 StringDictionaryLookupStub::GenerateNegativeLookup(masm,
150 miss_label,
151 &done,
152 properties,
153 name,
154 r1);
155 __ 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.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000196 __ movl(scratch, FieldOperand(name, String::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.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000208 __ movl(scratch, FieldOperand(name, String::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
346// Load a fast property out of a holder object (src). In-object properties
347// are loaded directly otherwise the property is loaded from the properties
348// fixed array.
349void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000350 Register dst,
351 Register src,
352 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000353 PropertyIndex index) {
354 if (index.is_header_index()) {
355 int offset = index.header_index() * kPointerSize;
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000356 __ movq(dst, FieldOperand(src, offset));
357 } else {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000358 // Adjust for the number of properties stored in the holder.
359 int slot = index.field_index() - holder->map()->inobject_properties();
360 if (slot < 0) {
361 // Get the property straight out of the holder.
362 int offset = holder->map()->instance_size() + (slot * kPointerSize);
363 __ movq(dst, FieldOperand(src, offset));
364 } else {
365 // Calculate the offset into the properties array.
366 int offset = slot * kPointerSize + FixedArray::kHeaderSize;
367 __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
368 __ movq(dst, FieldOperand(dst, offset));
369 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000370 }
371}
372
373
374static void PushInterceptorArguments(MacroAssembler* masm,
375 Register receiver,
376 Register holder,
377 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000378 Handle<JSObject> holder_obj) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000379 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000380 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
381 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
382 __ Move(kScratchRegister, interceptor);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000383 __ push(kScratchRegister);
384 __ push(receiver);
385 __ push(holder);
386 __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000387 __ PushAddress(ExternalReference::isolate_address());
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000388}
389
390
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000391static void CompileCallLoadPropertyWithInterceptor(
392 MacroAssembler* masm,
393 Register receiver,
394 Register holder,
395 Register name,
396 Handle<JSObject> holder_obj) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000397 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
398
399 ExternalReference ref =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000400 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
401 masm->isolate());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000402 __ Set(rax, 6);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000403 __ LoadAddress(rbx, ref);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000404
ager@chromium.orga1645e22009-09-09 19:27:10 +0000405 CEntryStub stub(1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000406 __ CallStub(&stub);
407}
408
409
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000410// Number of pointers to be reserved on stack for fast API call.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000411static const int kFastApiCallArguments = 4;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000412
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000413
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000414// Reserves space for the extra arguments to API function in the
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000415// caller's frame.
416//
417// These arguments are set by CheckPrototypes and GenerateFastApiCall.
418static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
419 // ----------- S t a t e -------------
420 // -- rsp[0] : return address
421 // -- rsp[8] : last argument in the internal frame of the caller
422 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +0000423 __ movq(scratch, Operand(rsp, 0));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000424 __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
ager@chromium.orgac091b72010-05-05 07:34:42 +0000425 __ movq(Operand(rsp, 0), scratch);
426 __ Move(scratch, Smi::FromInt(0));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000427 for (int i = 1; i <= kFastApiCallArguments; i++) {
428 __ movq(Operand(rsp, i * kPointerSize), scratch);
429 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000430}
431
432
433// Undoes the effects of ReserveSpaceForFastApiCall.
434static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
435 // ----------- S t a t e -------------
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000436 // -- rsp[0] : return address.
437 // -- rsp[8] : last fast api call extra argument.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000438 // -- ...
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000439 // -- rsp[kFastApiCallArguments * 8] : first fast api call extra argument.
440 // -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal
441 // frame.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000442 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +0000443 __ movq(scratch, Operand(rsp, 0));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000444 __ movq(Operand(rsp, kFastApiCallArguments * kPointerSize), scratch);
445 __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000446}
447
448
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000449// Generates call to API function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000450static void GenerateFastApiCall(MacroAssembler* masm,
451 const CallOptimization& optimization,
452 int argc) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000453 // ----------- S t a t e -------------
454 // -- rsp[0] : return address
455 // -- rsp[8] : object passing the type check
456 // (last fast api call extra argument,
457 // set by CheckPrototypes)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000458 // -- rsp[16] : api function
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000459 // (first fast api call extra argument)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000460 // -- rsp[24] : api call data
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000461 // -- rsp[32] : isolate
462 // -- rsp[40] : last argument
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000463 // -- ...
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000464 // -- rsp[(argc + 4) * 8] : first argument
465 // -- rsp[(argc + 5) * 8] : receiver
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000466 // -----------------------------------
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000467 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000468 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000469 __ LoadHeapObject(rdi, function);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000470 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
471
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000472 // Pass the additional arguments.
473 __ movq(Operand(rsp, 2 * kPointerSize), rdi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000474 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
475 Handle<Object> call_data(api_call_info->data());
476 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
477 __ Move(rcx, api_call_info);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000478 __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000479 __ movq(Operand(rsp, 3 * kPointerSize), rbx);
480 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000481 __ Move(Operand(rsp, 3 * kPointerSize), call_data);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000482 }
jkummerow@chromium.org3ee08a62012-04-13 13:01:33 +0000483 __ movq(kScratchRegister, ExternalReference::isolate_address());
484 __ movq(Operand(rsp, 4 * kPointerSize), kScratchRegister);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000485
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000486 // Prepare arguments.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000487 __ lea(rbx, Operand(rsp, 4 * kPointerSize));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000488
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000489#if defined(__MINGW64__)
490 Register arguments_arg = rcx;
491#elif defined(_WIN64)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000492 // Win64 uses first register--rcx--for returned value.
493 Register arguments_arg = rdx;
494#else
495 Register arguments_arg = rdi;
496#endif
497
498 // Allocate the v8::Arguments structure in the arguments' space since
499 // it's not controlled by GC.
500 const int kApiStackSpace = 4;
501
502 __ PrepareCallApiFunction(kApiStackSpace);
503
504 __ movq(StackSpaceOperand(0), rbx); // v8::Arguments::implicit_args_.
505 __ addq(rbx, Immediate(argc * kPointerSize));
506 __ movq(StackSpaceOperand(1), rbx); // v8::Arguments::values_.
507 __ Set(StackSpaceOperand(2), argc); // v8::Arguments::length_.
508 // v8::Arguments::is_construct_call_.
509 __ Set(StackSpaceOperand(3), 0);
510
511 // v8::InvocationCallback's argument.
512 __ lea(arguments_arg, StackSpaceOperand(0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000513
514 // Function address is a foreign pointer outside V8's heap.
515 Address function_address = v8::ToCData<Address>(api_call_info->callback());
516 __ CallApiFunctionAndReturn(function_address,
517 argc + kFastApiCallArguments + 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000518}
519
520
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000521class CallInterceptorCompiler BASE_EMBEDDED {
522 public:
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000523 CallInterceptorCompiler(StubCompiler* stub_compiler,
524 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000525 Register name,
526 Code::ExtraICState extra_ic_state)
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000527 : stub_compiler_(stub_compiler),
528 arguments_(arguments),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000529 name_(name),
530 extra_ic_state_(extra_ic_state) {}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000531
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000532 void Compile(MacroAssembler* masm,
533 Handle<JSObject> object,
534 Handle<JSObject> holder,
535 Handle<String> name,
536 LookupResult* lookup,
537 Register receiver,
538 Register scratch1,
539 Register scratch2,
540 Register scratch3,
541 Label* miss) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000542 ASSERT(holder->HasNamedInterceptor());
543 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
544
545 // Check that the receiver isn't a smi.
546 __ JumpIfSmi(receiver, miss);
547
548 CallOptimization optimization(lookup);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000549 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000550 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
551 holder, lookup, name, optimization, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000552 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000553 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
554 name, holder, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000555 }
556 }
557
558 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000559 void CompileCacheable(MacroAssembler* masm,
560 Handle<JSObject> object,
561 Register receiver,
562 Register scratch1,
563 Register scratch2,
564 Register scratch3,
565 Handle<JSObject> interceptor_holder,
566 LookupResult* lookup,
567 Handle<String> name,
568 const CallOptimization& optimization,
569 Label* miss_label) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000570 ASSERT(optimization.is_constant_call());
ager@chromium.org5c838252010-02-19 08:53:10 +0000571 ASSERT(!lookup->holder()->IsGlobalObject());
572
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000573 int depth1 = kInvalidProtoDepth;
574 int depth2 = kInvalidProtoDepth;
575 bool can_do_fast_api_call = false;
576 if (optimization.is_simple_api_call() &&
577 !lookup->holder()->IsGlobalObject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000578 depth1 = optimization.GetPrototypeDepthOfExpectedType(
579 object, interceptor_holder);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000580 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000581 depth2 = optimization.GetPrototypeDepthOfExpectedType(
582 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000583 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000584 can_do_fast_api_call =
585 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000586 }
587
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000588 Counters* counters = masm->isolate()->counters();
589 __ IncrementCounter(counters->call_const_interceptor(), 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000590
591 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000592 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000593 ReserveSpaceForFastApiCall(masm, scratch1);
594 }
595
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000596 // Check that the maps from receiver to interceptor's holder
597 // haven't changed and thus we can invoke interceptor.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000598 Label miss_cleanup;
599 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
600 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000601 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
602 scratch1, scratch2, scratch3,
603 name, depth1, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000604
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000605 // Invoke an interceptor and if it provides a value,
606 // branch to |regular_invoke|.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000607 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000608 LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
609 &regular_invoke);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000610
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000611 // Interceptor returned nothing for this property. Try to use cached
612 // constant function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000613
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000614 // Check that the maps from interceptor's holder to constant function's
615 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000616 if (*interceptor_holder != lookup->holder()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000617 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000618 Handle<JSObject>(lookup->holder()),
619 scratch1, scratch2, scratch3,
620 name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000621 } else {
622 // CheckPrototypes has a side effect of fetching a 'holder'
623 // for API (object which is instanceof for the signature). It's
624 // safe to omit it here, as if present, it should be fetched
625 // by the previous CheckPrototypes.
626 ASSERT(depth2 == kInvalidProtoDepth);
627 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000628
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000629 // Invoke function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000630 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000631 GenerateFastApiCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000632 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000633 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
634 ? CALL_AS_FUNCTION
635 : CALL_AS_METHOD;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000636 __ InvokeFunction(optimization.constant_function(), arguments_,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000637 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000638 }
639
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000640 // Deferred code for fast API call case---clean preallocated space.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000641 if (can_do_fast_api_call) {
642 __ bind(&miss_cleanup);
643 FreeSpaceForFastApiCall(masm, scratch1);
644 __ jmp(miss_label);
645 }
646
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000647 // Invoke a regular function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000648 __ bind(&regular_invoke);
649 if (can_do_fast_api_call) {
650 FreeSpaceForFastApiCall(masm, scratch1);
651 }
652 }
653
654 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000655 Handle<JSObject> object,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000656 Register receiver,
657 Register scratch1,
658 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000659 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000660 Handle<String> name,
661 Handle<JSObject> interceptor_holder,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000662 Label* miss_label) {
663 Register holder =
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000664 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000665 scratch1, scratch2, scratch3,
666 name, miss_label);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000667
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000668 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000669 // Save the name_ register across the call.
670 __ push(name_);
671
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000672 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000673
674 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000675 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
676 masm->isolate()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000677 6);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000678
679 // Restore the name_ register.
680 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000681
682 // Leave the internal frame.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000683 }
684
685 void LoadWithInterceptor(MacroAssembler* masm,
686 Register receiver,
687 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000688 Handle<JSObject> holder_obj,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000689 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000690 {
691 FrameScope scope(masm, StackFrame::INTERNAL);
692 __ push(holder); // Save the holder.
693 __ push(name_); // Save the name.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000694
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000695 CompileCallLoadPropertyWithInterceptor(masm,
696 receiver,
697 holder,
698 name_,
699 holder_obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000700
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000701 __ pop(name_); // Restore the name.
702 __ pop(receiver); // Restore the holder.
703 // Leave the internal frame.
704 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000705
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000706 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000707 __ j(not_equal, interceptor_succeeded);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000708 }
709
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000710 StubCompiler* stub_compiler_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000711 const ParameterCount& arguments_;
ager@chromium.org5c838252010-02-19 08:53:10 +0000712 Register name_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000713 Code::ExtraICState extra_ic_state_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000714};
715
716
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000717void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
718 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000719 Handle<Code> code = (kind == Code::LOAD_IC)
720 ? masm->isolate()->builtins()->LoadIC_Miss()
721 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
722 __ Jump(code, RelocInfo::CODE_TARGET);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000723}
724
725
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000726void StubCompiler::GenerateStoreMiss(MacroAssembler* masm, Code::Kind kind) {
727 ASSERT(kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC);
728 Handle<Code> code = (kind == Code::STORE_IC)
729 ? masm->isolate()->builtins()->StoreIC_Miss()
730 : masm->isolate()->builtins()->KeyedStoreIC_Miss();
731 __ Jump(code, RelocInfo::CODE_TARGET);
732}
733
734
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000735void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000736 Handle<Code> code =
737 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
738 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000739}
740
741
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000742// Both name_reg and receiver_reg are preserved on jumps to miss_label,
743// but may be destroyed if store is successful.
744void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000745 Handle<JSObject> object,
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000746 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000747 Handle<Map> transition,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000748 Handle<String> name,
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000749 Register receiver_reg,
750 Register name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000751 Register scratch1,
752 Register scratch2,
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000753 Label* miss_label) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000754 LookupResult lookup(masm->isolate());
755 object->Lookup(*name, &lookup);
756 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
757 // In sloppy mode, we could just return the value and be done. However, we
758 // might be in strict mode, where we have to throw. Since we cannot tell,
759 // go into slow case unconditionally.
760 __ jmp(miss_label);
761 return;
762 }
763
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000764 // Check that the map of the object hasn't changed.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000765 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
766 : REQUIRE_EXACT_MAP;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000767 __ CheckMap(receiver_reg, Handle<Map>(object->map()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000768 miss_label, DO_SMI_CHECK, mode);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000769
770 // Perform global security token check if needed.
771 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000772 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
773 }
774
775 // Check that we are allowed to write this.
776 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
777 JSObject* holder;
778 if (lookup.IsFound()) {
779 holder = lookup.holder();
780 } else {
781 // Find the top object.
782 holder = *object;
783 do {
784 holder = JSObject::cast(holder->GetPrototype());
785 } while (holder->GetPrototype()->IsJSObject());
786 }
787 // We need an extra register, push
788 __ push(name_reg);
789 Label miss_pop, done_check;
790 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
791 scratch1, scratch2, name, &miss_pop);
792 __ jmp(&done_check);
793 __ bind(&miss_pop);
794 __ pop(name_reg);
795 __ jmp(miss_label);
796 __ bind(&done_check);
797 __ pop(name_reg);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000798 }
799
800 // Stub never generated for non-global objects that require access
801 // checks.
802 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
803
804 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000805 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000806 // The properties must be extended before we can store the value.
807 // We jump to a runtime call that extends the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000808 __ pop(scratch1); // Return address.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000809 __ push(receiver_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000810 __ Push(transition);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000811 __ push(rax);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000812 __ push(scratch1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000813 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000814 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
815 masm->isolate()),
816 3,
817 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000818 return;
819 }
820
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000821 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +0000822 // Update the map of the object.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000823 __ Move(scratch1, transition);
824 __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000825
826 // Update the write barrier for the map field and pass the now unused
827 // name_reg as scratch register.
828 __ RecordWriteField(receiver_reg,
829 HeapObject::kMapOffset,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000830 scratch1,
verwaest@chromium.org37141392012-05-31 13:27:02 +0000831 name_reg,
832 kDontSaveFPRegs,
833 OMIT_REMEMBERED_SET,
834 OMIT_SMI_CHECK);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000835 }
836
837 // Adjust for the number of properties stored in the object. Even in the
838 // face of a transition we can use the old map here because the size of the
839 // object and the number of in-object properties is not going to change.
840 index -= object->map()->inobject_properties();
841
842 if (index < 0) {
843 // Set the property straight into the object.
844 int offset = object->map()->instance_size() + (index * kPointerSize);
845 __ movq(FieldOperand(receiver_reg, offset), rax);
846
847 // Update the write barrier for the array address.
848 // Pass the value being stored in the now unused name_reg.
849 __ movq(name_reg, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000850 __ RecordWriteField(
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000851 receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000852 } else {
853 // Write to the properties array.
854 int offset = index * kPointerSize + FixedArray::kHeaderSize;
855 // Get the properties array (optimistically).
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000856 __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
857 __ movq(FieldOperand(scratch1, offset), rax);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000858
859 // Update the write barrier for the array address.
860 // Pass the value being stored in the now unused name_reg.
861 __ movq(name_reg, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000862 __ RecordWriteField(
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000863 scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000864 }
865
866 // Return the value (register rax).
867 __ ret(0);
868}
869
870
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000871// Generate code to check that a global property cell is empty. Create
872// the property cell at compilation time if no cell exists for the
873// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000874static void GenerateCheckPropertyCell(MacroAssembler* masm,
875 Handle<GlobalObject> global,
876 Handle<String> name,
877 Register scratch,
878 Label* miss) {
879 Handle<JSGlobalPropertyCell> cell =
880 GlobalObject::EnsurePropertyCell(global, name);
881 ASSERT(cell->value()->IsTheHole());
882 __ Move(scratch, cell);
883 __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
884 masm->isolate()->factory()->the_hole_value());
885 __ j(not_equal, miss);
886}
887
888
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000889// Calls GenerateCheckPropertyCell for each global object in the prototype chain
890// from object to (but not including) holder.
891static void GenerateCheckPropertyCells(MacroAssembler* masm,
892 Handle<JSObject> object,
893 Handle<JSObject> holder,
894 Handle<String> name,
895 Register scratch,
896 Label* miss) {
897 Handle<JSObject> current = object;
898 while (!current.is_identical_to(holder)) {
899 if (current->IsGlobalObject()) {
900 GenerateCheckPropertyCell(masm,
901 Handle<GlobalObject>::cast(current),
902 name,
903 scratch,
904 miss);
905 }
906 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
907 }
908}
909
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000910#undef __
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000911#define __ ACCESS_MASM((masm()))
912
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000913
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000914Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
915 Register object_reg,
916 Handle<JSObject> holder,
917 Register holder_reg,
918 Register scratch1,
919 Register scratch2,
920 Handle<String> name,
921 int save_at_depth,
922 Label* miss) {
923 // Make sure there's no overlap between holder and object registers.
924 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
925 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
926 && !scratch2.is(scratch1));
927
928 // Keep track of the current object in register reg. On the first
929 // iteration, reg is an alias for object_reg, on later iterations,
930 // it is an alias for holder_reg.
931 Register reg = object_reg;
932 int depth = 0;
933
934 if (save_at_depth == depth) {
935 __ movq(Operand(rsp, kPointerSize), object_reg);
936 }
937
938 // Check the maps in the prototype chain.
939 // Traverse the prototype chain from the object and do map checks.
940 Handle<JSObject> current = object;
941 while (!current.is_identical_to(holder)) {
942 ++depth;
943
944 // Only global objects and objects that do not require access
945 // checks are allowed in stubs.
946 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
947
948 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
949 if (!current->HasFastProperties() &&
950 !current->IsJSGlobalObject() &&
951 !current->IsJSGlobalProxy()) {
952 if (!name->IsSymbol()) {
953 name = factory()->LookupSymbol(name);
954 }
955 ASSERT(current->property_dictionary()->FindEntry(*name) ==
956 StringDictionary::kNotFound);
957
958 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
959 scratch1, scratch2);
960
961 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
962 reg = holder_reg; // From now on the object will be in holder_reg.
963 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
964 } else {
965 bool in_new_space = heap()->InNewSpace(*prototype);
966 Handle<Map> current_map(current->map());
967 if (in_new_space) {
968 // Save the map in scratch1 for later.
969 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000970 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000971 __ CheckMap(reg, Handle<Map>(current_map),
972 miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
973
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000974 // Check access rights to the global object. This has to happen after
975 // the map check so that we know that the object is actually a global
976 // object.
977 if (current->IsJSGlobalProxy()) {
978 __ CheckAccessGlobalProxy(reg, scratch2, miss);
979 }
980 reg = holder_reg; // From now on the object will be in holder_reg.
981
982 if (in_new_space) {
983 // The prototype is in new space; we cannot store a reference to it
984 // in the code. Load it from the map.
985 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
986 } else {
987 // The prototype is in old space; load it directly.
988 __ Move(reg, prototype);
989 }
990 }
991
992 if (save_at_depth == depth) {
993 __ movq(Operand(rsp, kPointerSize), reg);
994 }
995
996 // Go to the next object in the prototype chain.
997 current = prototype;
998 }
999 ASSERT(current.is_identical_to(holder));
1000
1001 // Log the check depth.
1002 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1003
1004 // Check the holder map.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001005 __ CheckMap(reg, Handle<Map>(holder->map()),
1006 miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001007
1008 // Perform security check for access to the global object.
1009 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1010 if (current->IsJSGlobalProxy()) {
1011 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1012 }
1013
1014 // If we've skipped any global objects, it's not enough to verify that
1015 // their maps haven't changed. We also need to check that the property
1016 // cell for the property is still empty.
1017 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1018
1019 // Return the register containing the holder.
1020 return reg;
1021}
1022
1023
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001024void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1025 Handle<JSObject> holder,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001026 Register receiver,
1027 Register scratch1,
1028 Register scratch2,
1029 Register scratch3,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001030 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001031 Handle<String> name,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001032 Label* miss) {
1033 // Check that the receiver isn't a smi.
1034 __ JumpIfSmi(receiver, miss);
1035
1036 // Check the prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001037 Register reg = CheckPrototypes(
1038 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001039
1040 // Get the value from the properties.
1041 GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
1042 __ ret(0);
1043}
1044
1045
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001046void StubCompiler::GenerateDictionaryLoadCallback(Register receiver,
1047 Register name_reg,
1048 Register scratch1,
1049 Register scratch2,
1050 Register scratch3,
1051 Handle<AccessorInfo> callback,
1052 Handle<String> name,
1053 Label* miss) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001054 ASSERT(!receiver.is(scratch1));
1055 ASSERT(!receiver.is(scratch2));
1056 ASSERT(!receiver.is(scratch3));
1057
1058 // Load the properties dictionary.
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001059 Register dictionary = scratch1;
1060 __ movq(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
1061
1062 // Probe the dictionary.
1063 Label probe_done;
1064 StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
1065 miss,
1066 &probe_done,
1067 dictionary,
1068 name_reg,
1069 scratch2,
1070 scratch3);
1071 __ bind(&probe_done);
1072
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001073 // If probing finds an entry in the dictionary, scratch3 contains the
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001074 // index into the dictionary. Check that the value is the callback.
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001075 Register index = scratch3;
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001076 const int kElementsStartOffset =
1077 StringDictionary::kHeaderSize +
1078 StringDictionary::kElementsStartIndex * kPointerSize;
1079 const int kValueOffset = kElementsStartOffset + kPointerSize;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001080 __ movq(scratch2,
1081 Operand(dictionary, index, times_pointer_size,
1082 kValueOffset - kHeapObjectTag));
1083 __ movq(scratch3, callback, RelocInfo::EMBEDDED_OBJECT);
1084 __ cmpq(scratch2, scratch3);
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001085 __ j(not_equal, miss);
1086}
1087
1088
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001089void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1090 Handle<JSObject> holder,
1091 Register receiver,
1092 Register name_reg,
1093 Register scratch1,
1094 Register scratch2,
1095 Register scratch3,
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001096 Register scratch4,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001097 Handle<AccessorInfo> callback,
1098 Handle<String> name,
1099 Label* miss) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001100 // Check that the receiver isn't a smi.
1101 __ JumpIfSmi(receiver, miss);
1102
1103 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001104 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1105 scratch2, scratch3, name, miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001106
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001107 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1108 GenerateDictionaryLoadCallback(
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001109 reg, name_reg, scratch2, scratch3, scratch4, callback, name, miss);
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001110 }
1111
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001112 // Insert additional parameters into the stack frame above return address.
1113 ASSERT(!scratch2.is(reg));
1114 __ pop(scratch2); // Get return address to place it below.
1115
1116 __ push(receiver); // receiver
1117 __ push(reg); // holder
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001118 if (heap()->InNewSpace(callback->data())) {
1119 __ Move(scratch1, callback);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001120 __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); // data
1121 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001122 __ Push(Handle<Object>(callback->data()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001123 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001124 __ PushAddress(ExternalReference::isolate_address()); // isolate
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001125 __ push(name_reg); // name
1126 // Save a pointer to where we pushed the arguments pointer.
1127 // This will be passed as the const AccessorInfo& to the C++ callback.
1128
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001129#if defined(__MINGW64__)
1130 Register accessor_info_arg = rdx;
1131 Register name_arg = rcx;
1132#elif defined(_WIN64)
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001133 // Win64 uses first register--rcx--for returned value.
1134 Register accessor_info_arg = r8;
1135 Register name_arg = rdx;
1136#else
1137 Register accessor_info_arg = rsi;
1138 Register name_arg = rdi;
1139#endif
1140
1141 ASSERT(!name_arg.is(scratch2));
1142 __ movq(name_arg, rsp);
1143 __ push(scratch2); // Restore return address.
1144
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001145 // 4 elements array for v8::Arguments::values_ and handler for name.
1146 const int kStackSpace = 5;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001147
1148 // Allocate v8::AccessorInfo in non-GCed stack space.
1149 const int kArgStackSpace = 1;
1150
1151 __ PrepareCallApiFunction(kArgStackSpace);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001152 __ lea(rax, Operand(name_arg, 4 * kPointerSize));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001153
1154 // v8::AccessorInfo::args_.
1155 __ movq(StackSpaceOperand(0), rax);
1156
1157 // The context register (rsi) has been saved in PrepareCallApiFunction and
1158 // could be used to pass arguments.
1159 __ lea(accessor_info_arg, StackSpaceOperand(0));
1160
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001161 Address getter_address = v8::ToCData<Address>(callback->getter());
1162 __ CallApiFunctionAndReturn(getter_address, kStackSpace);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001163}
1164
1165
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001166void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1167 Handle<JSObject> holder,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001168 Register receiver,
1169 Register scratch1,
1170 Register scratch2,
1171 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001172 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001173 Handle<String> name,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001174 Label* miss) {
1175 // Check that the receiver isn't a smi.
1176 __ JumpIfSmi(receiver, miss);
1177
1178 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001179 CheckPrototypes(
1180 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001181
1182 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001183 __ LoadHeapObject(rax, value);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001184 __ ret(0);
1185}
1186
1187
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001188void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1189 Handle<JSObject> interceptor_holder,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001190 LookupResult* lookup,
1191 Register receiver,
1192 Register name_reg,
1193 Register scratch1,
1194 Register scratch2,
1195 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001196 Handle<String> name,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001197 Label* miss) {
1198 ASSERT(interceptor_holder->HasNamedInterceptor());
1199 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1200
1201 // Check that the receiver isn't a smi.
1202 __ JumpIfSmi(receiver, miss);
1203
1204 // So far the most popular follow ups for interceptor loads are FIELD
1205 // and CALLBACKS, so inline only them, other cases may be added
1206 // later.
1207 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001208 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001209 if (lookup->IsField()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001210 compile_followup_inline = true;
1211 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001212 lookup->GetCallbackObject()->IsAccessorInfo()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001213 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1214 compile_followup_inline = callback->getter() != NULL &&
1215 callback->IsCompatibleReceiver(*object);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001216 }
1217 }
1218
1219 if (compile_followup_inline) {
1220 // Compile the interceptor call, followed by inline code to load the
1221 // property from further up the prototype chain if the call fails.
1222 // Check that the maps haven't changed.
1223 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1224 scratch1, scratch2, scratch3,
1225 name, miss);
1226 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1227
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001228 // Preserve the receiver register explicitly whenever it is different from
1229 // the holder and it is needed should the interceptor return without any
1230 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1231 // the FIELD case might cause a miss during the prototype check.
1232 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1233 bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1234 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1235
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001236 // Save necessary data before invoking an interceptor.
1237 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001238 {
1239 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001240
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001241 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001242 __ push(receiver);
1243 }
1244 __ push(holder_reg);
1245 __ push(name_reg);
1246
1247 // Invoke an interceptor. Note: map checks from receiver to
1248 // interceptor's holder has been compiled before (see a caller
1249 // of this method.)
1250 CompileCallLoadPropertyWithInterceptor(masm(),
1251 receiver,
1252 holder_reg,
1253 name_reg,
1254 interceptor_holder);
1255
1256 // Check if interceptor provided a value for property. If it's
1257 // the case, return immediately.
1258 Label interceptor_failed;
1259 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
1260 __ j(equal, &interceptor_failed);
1261 frame_scope.GenerateLeaveFrame();
1262 __ ret(0);
1263
1264 __ bind(&interceptor_failed);
1265 __ pop(name_reg);
1266 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001267 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001268 __ pop(receiver);
1269 }
1270
1271 // Leave the internal frame.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001272 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001273
1274 // Check that the maps from interceptor's holder to lookup's holder
1275 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001276 if (must_perfrom_prototype_check) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001277 holder_reg = CheckPrototypes(interceptor_holder,
1278 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001279 Handle<JSObject>(lookup->holder()),
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001280 scratch1,
1281 scratch2,
1282 scratch3,
1283 name,
1284 miss);
1285 }
1286
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001287 if (lookup->IsField()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001288 // We found FIELD property in prototype chain of interceptor's holder.
1289 // Retrieve a field from field's holder.
1290 GenerateFastPropertyLoad(masm(), rax, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001291 Handle<JSObject>(lookup->holder()),
1292 lookup->GetFieldIndex());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001293 __ ret(0);
1294 } else {
1295 // We found CALLBACKS property in prototype chain of interceptor's
1296 // holder.
1297 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001298 Handle<AccessorInfo> callback(
1299 AccessorInfo::cast(lookup->GetCallbackObject()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001300 ASSERT(callback->getter() != NULL);
1301
1302 // Tail call to runtime.
1303 // Important invariant in CALLBACKS case: the code above must be
1304 // structured to never clobber |receiver| register.
1305 __ pop(scratch2); // return address
1306 __ push(receiver);
1307 __ push(holder_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001308 __ Move(holder_reg, callback);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001309 __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001310 __ PushAddress(ExternalReference::isolate_address());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001311 __ push(holder_reg);
1312 __ push(name_reg);
1313 __ push(scratch2); // restore return address
1314
1315 ExternalReference ref =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001316 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001317 isolate());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001318 __ TailCallExternalReference(ref, 6, 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001319 }
1320 } else { // !compile_followup_inline
1321 // Call the runtime system to load the interceptor.
1322 // Check that the maps haven't changed.
1323 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1324 scratch1, scratch2, scratch3,
1325 name, miss);
1326 __ pop(scratch2); // save old return address
1327 PushInterceptorArguments(masm(), receiver, holder_reg,
1328 name_reg, interceptor_holder);
1329 __ push(scratch2); // restore old return address
1330
1331 ExternalReference ref = ExternalReference(
lrn@chromium.org7516f052011-03-30 08:52:27 +00001332 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001333 __ TailCallExternalReference(ref, 6, 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001334 }
1335}
1336
1337
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001338void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001339 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001340 __ Cmp(rcx, name);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001341 __ j(not_equal, miss);
1342 }
1343}
1344
1345
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001346void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1347 Handle<JSObject> holder,
1348 Handle<String> name,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001349 Label* miss) {
1350 ASSERT(holder->IsGlobalObject());
1351
1352 // Get the number of arguments.
1353 const int argc = arguments().immediate();
1354
1355 // Get the receiver from the stack.
1356 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1357
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001358
1359 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001360 __ JumpIfSmi(rdx, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001361 CheckPrototypes(object, rdx, holder, rbx, rax, rdi, name, miss);
1362}
1363
1364
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001365void CallStubCompiler::GenerateLoadFunctionFromCell(
1366 Handle<JSGlobalPropertyCell> cell,
1367 Handle<JSFunction> function,
1368 Label* miss) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001369 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001370 __ Move(rdi, cell);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001371 __ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset));
1372
1373 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001374 if (heap()->InNewSpace(*function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001375 // We can't embed a pointer to a function in new space so we have
1376 // to verify that the shared function info is unchanged. This has
1377 // the nice side effect that multiple closures based on the same
1378 // function can all use this call IC. Before we load through the
1379 // function, we have to verify that it still is a function.
1380 __ JumpIfSmi(rdi, miss);
1381 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax);
1382 __ j(not_equal, miss);
1383
1384 // Check the shared function info. Make sure it hasn't changed.
1385 __ Move(rax, Handle<SharedFunctionInfo>(function->shared()));
1386 __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001387 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001388 __ Cmp(rdi, function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001389 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001390 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001391}
1392
1393
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001394void CallStubCompiler::GenerateMissBranch() {
1395 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001396 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1397 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001398 extra_state_);
1399 __ Jump(code, RelocInfo::CODE_TARGET);
1400}
1401
1402
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001403Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1404 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001405 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001406 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001407 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001408 // rcx : function name
1409 // rsp[0] : return address
1410 // rsp[8] : argument argc
1411 // rsp[16] : argument argc - 1
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001412 // ...
ager@chromium.org5c838252010-02-19 08:53:10 +00001413 // rsp[argc * 8] : argument 1
1414 // rsp[(argc + 1) * 8] : argument 0 = receiver
1415 // -----------------------------------
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001416 Label miss;
1417
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001418 GenerateNameCheck(name, &miss);
1419
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001420 // Get the receiver from the stack.
1421 const int argc = arguments().immediate();
1422 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1423
1424 // Check that the receiver isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001425 __ JumpIfSmi(rdx, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001426
1427 // Do the right check and compute the holder register.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001428 Register reg = CheckPrototypes(object, rdx, holder, rbx, rax, rdi,
1429 name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001430
1431 GenerateFastPropertyLoad(masm(), rdi, reg, holder, index);
1432
1433 // Check that the function really is a function.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001434 __ JumpIfSmi(rdi, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001435 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rbx);
1436 __ j(not_equal, &miss);
1437
1438 // Patch the receiver on the stack with the global proxy if
1439 // necessary.
1440 if (object->IsGlobalObject()) {
1441 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
1442 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
1443 }
1444
1445 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001446 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001447 ? CALL_AS_FUNCTION
1448 : CALL_AS_METHOD;
1449 __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
1450 NullCallWrapper(), call_kind);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001451
1452 // Handle call cache miss.
1453 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001454 GenerateMissBranch();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001455
1456 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001457 return GetCode(Code::FIELD, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001458}
1459
1460
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001461Handle<Code> CallStubCompiler::CompileArrayPushCall(
1462 Handle<Object> object,
1463 Handle<JSObject> holder,
1464 Handle<JSGlobalPropertyCell> cell,
1465 Handle<JSFunction> function,
1466 Handle<String> name) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001467 // ----------- S t a t e -------------
1468 // -- rcx : name
1469 // -- rsp[0] : return address
1470 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1471 // -- ...
1472 // -- rsp[(argc + 1) * 8] : receiver
1473 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +00001474
1475 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001476 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001477
1478 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001479 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001480
ager@chromium.orgac091b72010-05-05 07:34:42 +00001481 // Get the receiver from the stack.
1482 const int argc = arguments().immediate();
1483 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1484
1485 // Check that the receiver isn't a smi.
1486 __ JumpIfSmi(rdx, &miss);
1487
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001488 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
1489 name, &miss);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001490
1491 if (argc == 0) {
1492 // Noop, return the length.
1493 __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset));
1494 __ ret((argc + 1) * kPointerSize);
1495 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001496 Label call_builtin;
1497
ager@chromium.orgac091b72010-05-05 07:34:42 +00001498 if (argc == 1) { // Otherwise fall through to call builtin.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001499 Label attempt_to_grow_elements, with_write_barrier, check_double;
ager@chromium.orgac091b72010-05-05 07:34:42 +00001500
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001501 // Get the elements array of the object.
1502 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
1503
1504 // Check that the elements are in fast mode and writable.
1505 __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
1506 factory()->fixed_array_map());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001507 __ j(not_equal, &check_double);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001508
ager@chromium.orgac091b72010-05-05 07:34:42 +00001509 // Get the array's length into rax and calculate new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001510 __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001511 STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001512 __ addl(rax, Immediate(argc));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001513
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001514 // Get the elements' length into rcx.
1515 __ SmiToInteger32(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001516
1517 // Check if we could survive without allocation.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001518 __ cmpl(rax, rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001519 __ j(greater, &attempt_to_grow_elements);
1520
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001521 // Check if value is a smi.
1522 __ movq(rcx, Operand(rsp, argc * kPointerSize));
1523 __ JumpIfNotSmi(rcx, &with_write_barrier);
1524
ager@chromium.orgac091b72010-05-05 07:34:42 +00001525 // Save new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001526 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001527
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001528 // Store the value.
1529 __ movq(FieldOperand(rdi,
1530 rax,
1531 times_pointer_size,
1532 FixedArray::kHeaderSize - argc * kPointerSize),
1533 rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001534
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001535 __ Integer32ToSmi(rax, rax); // Return new length as smi.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001536 __ ret((argc + 1) * kPointerSize);
1537
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001538 __ bind(&check_double);
1539
1540 // Check that the elements are in double mode.
1541 __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
1542 factory()->fixed_double_array_map());
1543 __ j(not_equal, &call_builtin);
1544
1545 // Get the array's length into rax and calculate new length.
1546 __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset));
1547 STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue);
1548 __ addl(rax, Immediate(argc));
1549
1550 // Get the elements' length into rcx.
1551 __ SmiToInteger32(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
1552
1553 // Check if we could survive without allocation.
1554 __ cmpl(rax, rcx);
1555 __ j(greater, &call_builtin);
1556
1557 __ movq(rcx, Operand(rsp, argc * kPointerSize));
1558 __ StoreNumberToDoubleElements(
1559 rcx, rdi, rax, xmm0, &call_builtin, argc * kDoubleSize);
1560
1561 // Save new length.
1562 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
1563 __ Integer32ToSmi(rax, rax); // Return new length as smi.
1564 __ ret((argc + 1) * kPointerSize);
1565
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001566 __ bind(&with_write_barrier);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001567
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001568 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
1569
1570 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1571 Label fast_object, not_fast_object;
1572 __ CheckFastObjectElements(rbx, &not_fast_object, Label::kNear);
1573 __ jmp(&fast_object);
1574 // In case of fast smi-only, convert to fast object, otherwise bail out.
1575 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001576 __ CheckFastSmiElements(rbx, &call_builtin);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001577 __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset),
1578 factory()->heap_number_map());
1579 __ j(equal, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001580 // rdx: receiver
1581 // rbx: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001582
1583 Label try_holey_map;
1584 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001585 FAST_ELEMENTS,
1586 rbx,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001587 rdi,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001588 &try_holey_map);
1589
1590 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001591 GenerateMapChangeElementsTransition(masm(),
1592 DONT_TRACK_ALLOCATION_SITE,
1593 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001594 // Restore edi.
1595 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
1596 __ jmp(&fast_object);
1597
1598 __ bind(&try_holey_map);
1599 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1600 FAST_HOLEY_ELEMENTS,
1601 rbx,
1602 rdi,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001603 &call_builtin);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001604 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001605 GenerateMapChangeElementsTransition(masm(),
1606 DONT_TRACK_ALLOCATION_SITE,
1607 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001608 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001609 __ bind(&fast_object);
1610 } else {
1611 __ CheckFastObjectElements(rbx, &call_builtin);
1612 }
1613
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001614 // Save new length.
1615 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001616
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001617 // Store the value.
1618 __ lea(rdx, FieldOperand(rdi,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001619 rax, times_pointer_size,
1620 FixedArray::kHeaderSize - argc * kPointerSize));
1621 __ movq(Operand(rdx, 0), rcx);
1622
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001623 __ RecordWrite(rdi, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001624 OMIT_SMI_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001625
1626 __ Integer32ToSmi(rax, rax); // Return new length as smi.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001627 __ ret((argc + 1) * kPointerSize);
1628
1629 __ bind(&attempt_to_grow_elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001630 if (!FLAG_inline_new) {
1631 __ jmp(&call_builtin);
1632 }
1633
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001634 __ movq(rbx, Operand(rsp, argc * kPointerSize));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001635 // Growing elements that are SMI-only requires special handling in case
1636 // the new element is non-Smi. For now, delegate to the builtin.
1637 Label no_fast_elements_check;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001638 __ JumpIfSmi(rbx, &no_fast_elements_check);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001639 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
1640 __ CheckFastObjectElements(rcx, &call_builtin, Label::kFar);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001641 __ bind(&no_fast_elements_check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001642
ager@chromium.orgac091b72010-05-05 07:34:42 +00001643 ExternalReference new_space_allocation_top =
lrn@chromium.org7516f052011-03-30 08:52:27 +00001644 ExternalReference::new_space_allocation_top_address(isolate());
ager@chromium.orgac091b72010-05-05 07:34:42 +00001645 ExternalReference new_space_allocation_limit =
lrn@chromium.org7516f052011-03-30 08:52:27 +00001646 ExternalReference::new_space_allocation_limit_address(isolate());
ager@chromium.orgac091b72010-05-05 07:34:42 +00001647
1648 const int kAllocationDelta = 4;
1649 // Load top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001650 __ Load(rcx, new_space_allocation_top);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001651
1652 // Check if it's the end of elements.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001653 __ lea(rdx, FieldOperand(rdi,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001654 rax, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001655 FixedArray::kHeaderSize - argc * kPointerSize));
1656 __ cmpq(rdx, rcx);
1657 __ j(not_equal, &call_builtin);
1658 __ addq(rcx, Immediate(kAllocationDelta * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001659 Operand limit_operand =
1660 masm()->ExternalOperand(new_space_allocation_limit);
1661 __ cmpq(rcx, limit_operand);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001662 __ j(above, &call_builtin);
1663
1664 // We fit and could grow elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001665 __ Store(new_space_allocation_top, rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001666
1667 // Push the argument...
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001668 __ movq(Operand(rdx, 0), rbx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001669 // ... and fill the rest with holes.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001670 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001671 for (int i = 1; i < kAllocationDelta; i++) {
1672 __ movq(Operand(rdx, i * kPointerSize), kScratchRegister);
1673 }
1674
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001675 // We know the elements array is in new space so we don't need the
1676 // remembered set, but we just pushed a value onto it so we may have to
1677 // tell the incremental marker to rescan the object that we just grew. We
1678 // don't need to worry about the holes because they are in old space and
1679 // already marked black.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001680 __ RecordWrite(rdi, rdx, rbx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001681
ager@chromium.orgac091b72010-05-05 07:34:42 +00001682 // Restore receiver to rdx as finish sequence assumes it's here.
1683 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1684
1685 // Increment element's and array's sizes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001686 __ SmiAddConstant(FieldOperand(rdi, FixedArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001687 Smi::FromInt(kAllocationDelta));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001688
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001689 // Make new length a smi before returning it.
1690 __ Integer32ToSmi(rax, rax);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001691 __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001692
ager@chromium.orgac091b72010-05-05 07:34:42 +00001693 __ ret((argc + 1) * kPointerSize);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001694 }
1695
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001696 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001697 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001698 isolate()),
ager@chromium.orgac091b72010-05-05 07:34:42 +00001699 argc + 1,
1700 1);
1701 }
1702
1703 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001704 GenerateMissBranch();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001705
1706 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001707 return GetCode(function);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001708}
1709
1710
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001711Handle<Code> CallStubCompiler::CompileArrayPopCall(
1712 Handle<Object> object,
1713 Handle<JSObject> holder,
1714 Handle<JSGlobalPropertyCell> cell,
1715 Handle<JSFunction> function,
1716 Handle<String> name) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001717 // ----------- S t a t e -------------
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001718 // -- rcx : name
1719 // -- rsp[0] : return address
1720 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
ager@chromium.orgac091b72010-05-05 07:34:42 +00001721 // -- ...
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001722 // -- rsp[(argc + 1) * 8] : receiver
ager@chromium.orgac091b72010-05-05 07:34:42 +00001723 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +00001724
1725 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001726 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001727
1728 Label miss, return_undefined, call_builtin;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001729 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001730
ager@chromium.orgac091b72010-05-05 07:34:42 +00001731 // Get the receiver from the stack.
1732 const int argc = arguments().immediate();
1733 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1734
1735 // Check that the receiver isn't a smi.
1736 __ JumpIfSmi(rdx, &miss);
1737
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001738 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
1739 name, &miss);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001740
1741 // Get the elements array of the object.
1742 __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
1743
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001744 // Check that the elements are in fast mode and writable.
1745 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
1746 Heap::kFixedArrayMapRootIndex);
1747 __ j(not_equal, &call_builtin);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001748
1749 // Get the array's length into rcx and calculate new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001750 __ SmiToInteger32(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
1751 __ subl(rcx, Immediate(1));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001752 __ j(negative, &return_undefined);
1753
1754 // Get the last element.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001755 __ LoadRoot(r9, Heap::kTheHoleValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001756 __ movq(rax, FieldOperand(rbx,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001757 rcx, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001758 FixedArray::kHeaderSize));
1759 // Check if element is already the hole.
1760 __ cmpq(rax, r9);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001761 // If so, call slow-case to also check prototypes for value.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001762 __ j(equal, &call_builtin);
1763
1764 // Set the array's length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001765 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001766
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001767 // Fill with the hole and return original value.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001768 __ movq(FieldOperand(rbx,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001769 rcx, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001770 FixedArray::kHeaderSize),
1771 r9);
1772 __ ret((argc + 1) * kPointerSize);
1773
1774 __ bind(&return_undefined);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001775 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001776 __ ret((argc + 1) * kPointerSize);
1777
1778 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001779 __ TailCallExternalReference(
lrn@chromium.org7516f052011-03-30 08:52:27 +00001780 ExternalReference(Builtins::c_ArrayPop, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001781 argc + 1,
1782 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001783
ager@chromium.orgac091b72010-05-05 07:34:42 +00001784 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001785 GenerateMissBranch();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001786
1787 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001788 return GetCode(function);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001789}
1790
1791
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001792Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1793 Handle<Object> object,
1794 Handle<JSObject> holder,
1795 Handle<JSGlobalPropertyCell> cell,
1796 Handle<JSFunction> function,
1797 Handle<String> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001798 // ----------- S t a t e -------------
1799 // -- rcx : function name
1800 // -- rsp[0] : return address
1801 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1802 // -- ...
1803 // -- rsp[(argc + 1) * 8] : receiver
1804 // -----------------------------------
1805
1806 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001807 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001808
1809 const int argc = arguments().immediate();
1810
1811 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001812 Label name_miss;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001813 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001814 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001815 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001816 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001817 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001818 index_out_of_range_label = &miss;
1819 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001820 GenerateNameCheck(name, &name_miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001821
1822 // Check that the maps starting from the prototype haven't changed.
1823 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1824 Context::STRING_FUNCTION_INDEX,
1825 rax,
1826 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001827 ASSERT(!object.is_identical_to(holder));
1828 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1829 rax, holder, rbx, rdx, rdi, name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001830
1831 Register receiver = rbx;
1832 Register index = rdi;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001833 Register result = rax;
1834 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
1835 if (argc > 0) {
1836 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
1837 } else {
1838 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1839 }
1840
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001841 StringCharCodeAtGenerator generator(receiver,
1842 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001843 result,
1844 &miss, // When not a string.
1845 &miss, // When not a number.
1846 index_out_of_range_label,
1847 STRING_INDEX_IS_NUMBER);
1848 generator.GenerateFast(masm());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001849 __ ret((argc + 1) * kPointerSize);
1850
1851 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001852 generator.GenerateSlow(masm(), call_helper);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001853
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001854 if (index_out_of_range.is_linked()) {
1855 __ bind(&index_out_of_range);
1856 __ LoadRoot(rax, Heap::kNanValueRootIndex);
1857 __ ret((argc + 1) * kPointerSize);
1858 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001859
1860 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001861 // Restore function name in rcx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001862 __ Move(rcx, name);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001863 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001864 GenerateMissBranch();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001865
1866 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001867 return GetCode(function);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001868}
1869
1870
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001871Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1872 Handle<Object> object,
1873 Handle<JSObject> holder,
1874 Handle<JSGlobalPropertyCell> cell,
1875 Handle<JSFunction> function,
1876 Handle<String> name) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001877 // ----------- S t a t e -------------
1878 // -- rcx : function name
1879 // -- rsp[0] : return address
1880 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1881 // -- ...
1882 // -- rsp[(argc + 1) * 8] : receiver
1883 // -----------------------------------
1884
1885 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001886 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001887
1888 const int argc = arguments().immediate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001889 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001890 Label name_miss;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001891 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001892 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001893 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001894 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001895 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001896 index_out_of_range_label = &miss;
1897 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001898 GenerateNameCheck(name, &name_miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001899
1900 // Check that the maps starting from the prototype haven't changed.
1901 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1902 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001903 rax,
1904 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001905 ASSERT(!object.is_identical_to(holder));
1906 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1907 rax, holder, rbx, rdx, rdi, name, &miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001908
1909 Register receiver = rax;
1910 Register index = rdi;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001911 Register scratch = rdx;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001912 Register result = rax;
1913 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
1914 if (argc > 0) {
1915 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
1916 } else {
1917 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1918 }
1919
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001920 StringCharAtGenerator generator(receiver,
1921 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001922 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001923 result,
1924 &miss, // When not a string.
1925 &miss, // When not a number.
1926 index_out_of_range_label,
1927 STRING_INDEX_IS_NUMBER);
1928 generator.GenerateFast(masm());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001929 __ ret((argc + 1) * kPointerSize);
1930
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001931 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001932 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001933
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001934 if (index_out_of_range.is_linked()) {
1935 __ bind(&index_out_of_range);
1936 __ LoadRoot(rax, Heap::kEmptyStringRootIndex);
1937 __ ret((argc + 1) * kPointerSize);
1938 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001939 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001940 // Restore function name in rcx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001941 __ Move(rcx, name);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001942 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001943 GenerateMissBranch();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001944
1945 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001946 return GetCode(function);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001947}
1948
1949
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001950Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1951 Handle<Object> object,
1952 Handle<JSObject> holder,
1953 Handle<JSGlobalPropertyCell> cell,
1954 Handle<JSFunction> function,
1955 Handle<String> name) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001956 // ----------- S t a t e -------------
1957 // -- rcx : function name
1958 // -- rsp[0] : return address
1959 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1960 // -- ...
1961 // -- rsp[(argc + 1) * 8] : receiver
1962 // -----------------------------------
1963
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001964 // If the object is not a JSObject or we got an unexpected number of
1965 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001966 const int argc = arguments().immediate();
1967 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001968
1969 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001970 GenerateNameCheck(name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001971
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001972 if (cell.is_null()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001973 __ movq(rdx, Operand(rsp, 2 * kPointerSize));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001974 __ JumpIfSmi(rdx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001975 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
1976 name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001977 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001978 ASSERT(cell->value() == *function);
1979 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1980 &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001981 GenerateLoadFunctionFromCell(cell, function, &miss);
1982 }
1983
1984 // Load the char code argument.
1985 Register code = rbx;
1986 __ movq(code, Operand(rsp, 1 * kPointerSize));
1987
1988 // Check the code is a smi.
1989 Label slow;
1990 __ JumpIfNotSmi(code, &slow);
1991
1992 // Convert the smi code to uint16.
1993 __ SmiAndConstant(code, code, Smi::FromInt(0xffff));
1994
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001995 StringCharFromCodeGenerator generator(code, rax);
1996 generator.GenerateFast(masm());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001997 __ ret(2 * kPointerSize);
1998
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001999 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002000 generator.GenerateSlow(masm(), call_helper);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002001
2002 // Tail call the full function. We do not have to patch the receiver
2003 // because the function makes no use of it.
2004 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002005 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002006 ? CALL_AS_FUNCTION
2007 : CALL_AS_METHOD;
2008 __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2009 NullCallWrapper(), call_kind);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002010
2011 __ bind(&miss);
2012 // rcx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002013 GenerateMissBranch();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002014
2015 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002016 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002017}
2018
2019
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002020Handle<Code> CallStubCompiler::CompileMathFloorCall(
2021 Handle<Object> object,
2022 Handle<JSObject> holder,
2023 Handle<JSGlobalPropertyCell> cell,
2024 Handle<JSFunction> function,
2025 Handle<String> name) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002026 // TODO(872): implement this.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002027 return Handle<Code>::null();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002028}
2029
2030
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002031Handle<Code> CallStubCompiler::CompileMathAbsCall(
2032 Handle<Object> object,
2033 Handle<JSObject> holder,
2034 Handle<JSGlobalPropertyCell> cell,
2035 Handle<JSFunction> function,
2036 Handle<String> name) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002037 // ----------- S t a t e -------------
2038 // -- rcx : function name
2039 // -- rsp[0] : return address
2040 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
2041 // -- ...
2042 // -- rsp[(argc + 1) * 8] : receiver
2043 // -----------------------------------
2044
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002045 // If the object is not a JSObject or we got an unexpected number of
2046 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002047 const int argc = arguments().immediate();
2048 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002049
2050 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002051 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002052
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002053 if (cell.is_null()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002054 __ movq(rdx, Operand(rsp, 2 * kPointerSize));
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002055 __ JumpIfSmi(rdx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002056 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
2057 name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002058 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002059 ASSERT(cell->value() == *function);
2060 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2061 &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002062 GenerateLoadFunctionFromCell(cell, function, &miss);
2063 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002064 // Load the (only) argument into rax.
2065 __ movq(rax, Operand(rsp, 1 * kPointerSize));
2066
2067 // Check if the argument is a smi.
2068 Label not_smi;
2069 STATIC_ASSERT(kSmiTag == 0);
2070 __ JumpIfNotSmi(rax, &not_smi);
2071 __ SmiToInteger32(rax, rax);
2072
2073 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2074 // otherwise.
2075 __ movl(rbx, rax);
2076 __ sarl(rbx, Immediate(kBitsPerInt - 1));
2077
2078 // Do bitwise not or do nothing depending on ebx.
2079 __ xorl(rax, rbx);
2080
2081 // Add 1 or do nothing depending on ebx.
2082 __ subl(rax, rbx);
2083
2084 // If the result is still negative, go to the slow case.
2085 // This only happens for the most negative smi.
2086 Label slow;
2087 __ j(negative, &slow);
2088
2089 // Smi case done.
2090 __ Integer32ToSmi(rax, rax);
2091 __ ret(2 * kPointerSize);
2092
2093 // Check if the argument is a heap number and load its value.
2094 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002095 __ CheckMap(rax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002096 __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
2097
2098 // Check the sign of the argument. If the argument is positive,
2099 // just return it.
2100 Label negative_sign;
2101 const int sign_mask_shift =
2102 (HeapNumber::kExponentOffset - HeapNumber::kValueOffset) * kBitsPerByte;
2103 __ movq(rdi, static_cast<int64_t>(HeapNumber::kSignMask) << sign_mask_shift,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00002104 RelocInfo::NONE64);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002105 __ testq(rbx, rdi);
2106 __ j(not_zero, &negative_sign);
2107 __ ret(2 * kPointerSize);
2108
2109 // If the argument is negative, clear the sign, and return a new
2110 // number. We still have the sign mask in rdi.
2111 __ bind(&negative_sign);
2112 __ xor_(rbx, rdi);
2113 __ AllocateHeapNumber(rax, rdx, &slow);
2114 __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rbx);
2115 __ ret(2 * kPointerSize);
2116
2117 // Tail call the full function. We do not have to patch the receiver
2118 // because the function makes no use of it.
2119 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002120 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002121 ? CALL_AS_FUNCTION
2122 : CALL_AS_METHOD;
2123 __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2124 NullCallWrapper(), call_kind);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002125
2126 __ bind(&miss);
2127 // rcx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002128 GenerateMissBranch();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002129
2130 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002131 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002132}
2133
2134
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002135Handle<Code> CallStubCompiler::CompileFastApiCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002136 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002137 Handle<Object> object,
2138 Handle<JSObject> holder,
2139 Handle<JSGlobalPropertyCell> cell,
2140 Handle<JSFunction> function,
2141 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002142 ASSERT(optimization.is_simple_api_call());
2143 // Bail out if object is a global object as we don't want to
2144 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002145 if (object->IsGlobalObject()) return Handle<Code>::null();
2146 if (!cell.is_null()) return Handle<Code>::null();
2147 if (!object->IsJSObject()) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002148 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002149 Handle<JSObject>::cast(object), holder);
2150 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002151
2152 Label miss, miss_before_stack_reserved;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002153 GenerateNameCheck(name, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002154
2155 // Get the receiver from the stack.
2156 const int argc = arguments().immediate();
2157 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2158
2159 // Check that the receiver isn't a smi.
2160 __ JumpIfSmi(rdx, &miss_before_stack_reserved);
2161
lrn@chromium.org7516f052011-03-30 08:52:27 +00002162 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002163 __ IncrementCounter(counters->call_const(), 1);
2164 __ IncrementCounter(counters->call_const_fast_api(), 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002165
2166 // Allocate space for v8::Arguments implicit values. Must be initialized
2167 // before calling any runtime function.
2168 __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2169
2170 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002171 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
2172 name, depth, &miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002173
2174 // Move the return address on top of the stack.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002175 __ movq(rax, Operand(rsp, 4 * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002176 __ movq(Operand(rsp, 0 * kPointerSize), rax);
2177
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002178 GenerateFastApiCall(masm(), optimization, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002179
2180 __ bind(&miss);
2181 __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2182
2183 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002184 GenerateMissBranch();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002185
2186 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002187 return GetCode(function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002188}
2189
2190
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002191Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2192 Handle<JSObject> holder,
2193 Handle<JSFunction> function,
2194 Handle<String> name,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002195 CheckType check) {
2196 // ----------- S t a t e -------------
2197 // rcx : function name
2198 // rsp[0] : return address
2199 // rsp[8] : argument argc
2200 // rsp[16] : argument argc - 1
2201 // ...
2202 // rsp[argc * 8] : argument 1
2203 // rsp[(argc + 1) * 8] : argument 0 = receiver
2204 // -----------------------------------
2205
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002206 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002207 Handle<Code> code = CompileCustomCall(object, holder,
2208 Handle<JSGlobalPropertyCell>::null(),
2209 function, name);
2210 // A null handle means bail out to the regular compiler code below.
2211 if (!code.is_null()) return code;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002212 }
2213
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002214 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002215 GenerateNameCheck(name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002216
2217 // Get the receiver from the stack.
2218 const int argc = arguments().immediate();
2219 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2220
2221 // Check that the receiver isn't a smi.
2222 if (check != NUMBER_CHECK) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002223 __ JumpIfSmi(rdx, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002224 }
2225
2226 // Make sure that it's okay not to patch the on stack receiver
2227 // unless we're doing a receiver map check.
2228 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2229
lrn@chromium.org7516f052011-03-30 08:52:27 +00002230 Counters* counters = isolate()->counters();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002231 switch (check) {
2232 case RECEIVER_MAP_CHECK:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002233 __ IncrementCounter(counters->call_const(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002234
2235 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002236 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax,
2237 rdi, name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002238
2239 // Patch the receiver on the stack with the global proxy if
2240 // necessary.
2241 if (object->IsGlobalObject()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002242 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
2243 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
2244 }
2245 break;
2246
2247 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002248 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002249 // Check that the object is a two-byte string or a symbol.
2250 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
2251 __ j(above_equal, &miss);
2252 // Check that the maps starting from the prototype haven't changed.
2253 GenerateDirectLoadGlobalFunctionPrototype(
2254 masm(), Context::STRING_FUNCTION_INDEX, rax, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002255 CheckPrototypes(
2256 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2257 rax, holder, rbx, rdx, rdi, name, &miss);
2258 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002259 // Calling non-strict non-builtins with a value as the receiver
2260 // requires boxing.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002261 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002262 }
2263 break;
2264
2265 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002266 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002267 Label fast;
2268 // Check that the object is a smi or a heap number.
2269 __ JumpIfSmi(rdx, &fast);
2270 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax);
2271 __ j(not_equal, &miss);
2272 __ bind(&fast);
2273 // Check that the maps starting from the prototype haven't changed.
2274 GenerateDirectLoadGlobalFunctionPrototype(
2275 masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002276 CheckPrototypes(
2277 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2278 rax, holder, rbx, rdx, rdi, name, &miss);
2279 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002280 // Calling non-strict non-builtins with a value as the receiver
2281 // requires boxing.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002282 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002283 }
2284 break;
2285
2286 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002287 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002288 Label fast;
2289 // Check that the object is a boolean.
2290 __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
2291 __ j(equal, &fast);
2292 __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
2293 __ j(not_equal, &miss);
2294 __ bind(&fast);
2295 // Check that the maps starting from the prototype haven't changed.
2296 GenerateDirectLoadGlobalFunctionPrototype(
2297 masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002298 CheckPrototypes(
2299 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2300 rax, holder, rbx, rdx, rdi, name, &miss);
2301 } else {
2302 // Calling non-strict non-builtins with a value as the receiver
2303 // requires boxing.
2304 __ jmp(&miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002305 }
2306 break;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002307 }
2308
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002309 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002310 ? CALL_AS_FUNCTION
2311 : CALL_AS_METHOD;
2312 __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2313 NullCallWrapper(), call_kind);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002314
2315 // Handle call cache miss.
2316 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002317 GenerateMissBranch();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002318
2319 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002320 return GetCode(function);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002321}
2322
2323
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002324Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2325 Handle<JSObject> holder,
2326 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002327 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00002328 // rcx : function name
2329 // rsp[0] : return address
2330 // rsp[8] : argument argc
2331 // rsp[16] : argument argc - 1
2332 // ...
2333 // rsp[argc * 8] : argument 1
2334 // rsp[(argc + 1) * 8] : argument 0 = receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002335 // -----------------------------------
2336 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002337 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002338
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002339 // Get the number of arguments.
2340 const int argc = arguments().immediate();
2341
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002342 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002343 LookupPostInterceptor(holder, name, &lookup);
2344
2345 // Get the receiver from the stack.
2346 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2347
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002348 CallInterceptorCompiler compiler(this, arguments(), rcx, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002349 compiler.Compile(masm(), object, holder, name, &lookup, rdx, rbx, rdi, rax,
2350 &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002351
2352 // Restore receiver.
2353 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2354
2355 // Check that the function really is a function.
ager@chromium.org4af710e2009-09-15 12:20:11 +00002356 __ JumpIfSmi(rax, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002357 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2358 __ j(not_equal, &miss);
2359
2360 // Patch the receiver on the stack with the global proxy if
2361 // necessary.
2362 if (object->IsGlobalObject()) {
2363 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
2364 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
2365 }
2366
2367 // Invoke the function.
2368 __ movq(rdi, rax);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002369 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002370 ? CALL_AS_FUNCTION
2371 : CALL_AS_METHOD;
2372 __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
2373 NullCallWrapper(), call_kind);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002374
2375 // Handle load cache miss.
2376 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002377 GenerateMissBranch();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002378
2379 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002380 return GetCode(Code::INTERCEPTOR, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002381}
2382
2383
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002384Handle<Code> CallStubCompiler::CompileCallGlobal(
2385 Handle<JSObject> object,
2386 Handle<GlobalObject> holder,
2387 Handle<JSGlobalPropertyCell> cell,
2388 Handle<JSFunction> function,
2389 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002390 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00002391 // rcx : function name
2392 // rsp[0] : return address
2393 // rsp[8] : argument argc
2394 // rsp[16] : argument argc - 1
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002395 // ...
ager@chromium.org5c838252010-02-19 08:53:10 +00002396 // rsp[argc * 8] : argument 1
2397 // rsp[(argc + 1) * 8] : argument 0 = receiver
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002398 // -----------------------------------
2399
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002400 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002401 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2402 // A null handle means bail out to the regular compiler code below.
2403 if (!code.is_null()) return code;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002404 }
2405
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002406 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002407 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002408
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002409 // Get the number of arguments.
2410 const int argc = arguments().immediate();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002411 GenerateGlobalReceiverCheck(object, holder, name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002412 GenerateLoadFunctionFromCell(cell, function, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002413
2414 // Patch the receiver on the stack with the global proxy.
2415 if (object->IsGlobalObject()) {
2416 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
2417 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
2418 }
2419
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002420 // Set up the context (function already in rdi).
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002421 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
2422
2423 // Jump to the cached code (tail call).
lrn@chromium.org7516f052011-03-30 08:52:27 +00002424 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002425 __ IncrementCounter(counters->call_global_inline(), 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002426 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002427 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002428 ? CALL_AS_FUNCTION
2429 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002430 // We call indirectly through the code field in the function to
2431 // allow recompilation to take effect without changing any of the
2432 // call sites.
2433 __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
2434 __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION,
2435 NullCallWrapper(), call_kind);
2436
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002437 // Handle call cache miss.
2438 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002439 __ IncrementCounter(counters->call_global_inline_miss(), 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002440 GenerateMissBranch();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002441
2442 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002443 return GetCode(Code::NORMAL, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002444}
2445
2446
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002447Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002448 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002449 Handle<Map> transition,
2450 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002451 // ----------- S t a t e -------------
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002452 // -- rax : value
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002453 // -- rcx : name
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002454 // -- rdx : receiver
2455 // -- rsp[0] : return address
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002456 // -----------------------------------
2457 Label miss;
2458
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002459 // Generate store field code. Preserves receiver and name on jump to miss.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002460 GenerateStoreField(masm(),
2461 object,
2462 index,
2463 transition,
2464 name,
2465 rdx, rcx, rbx, rdi,
2466 &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002467
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002468 // Handle store cache miss.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002469 __ bind(&miss);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002470 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002471 __ Jump(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002472
2473 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002474 return GetCode(transition.is_null()
2475 ? Code::FIELD
2476 : Code::MAP_TRANSITION, name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002477}
2478
2479
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002480Handle<Code> StoreStubCompiler::CompileStoreCallback(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002481 Handle<String> name,
2482 Handle<JSObject> receiver,
2483 Handle<JSObject> holder,
2484 Handle<AccessorInfo> callback) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002485 // ----------- S t a t e -------------
2486 // -- rax : value
2487 // -- rcx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002488 // -- rdx : receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002489 // -- rsp[0] : return address
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002490 // -----------------------------------
2491 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002492 // Check that the maps haven't changed.
2493 __ JumpIfSmi(rdx, &miss);
2494 CheckPrototypes(receiver, rdx, holder, rbx, r8, rdi, name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002495
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002496 // Stub never generated for non-global objects that require access checks.
2497 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002498
2499 __ pop(rbx); // remove the return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002500 __ push(rdx); // receiver
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002501 __ Push(callback); // callback info
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002502 __ push(rcx); // name
2503 __ push(rax); // value
2504 __ push(rbx); // restore return address
2505
2506 // Do tail-call to the runtime system.
2507 ExternalReference store_callback_property =
lrn@chromium.org7516f052011-03-30 08:52:27 +00002508 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002509 __ TailCallExternalReference(store_callback_property, 4, 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002510
2511 // Handle store cache miss.
2512 __ bind(&miss);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002513 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002514 __ Jump(ic, RelocInfo::CODE_TARGET);
2515
2516 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002517 return GetCode(Code::CALLBACKS, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002518}
2519
2520
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002521#undef __
2522#define __ ACCESS_MASM(masm)
2523
2524
2525void StoreStubCompiler::GenerateStoreViaSetter(
2526 MacroAssembler* masm,
2527 Handle<JSFunction> setter) {
2528 // ----------- S t a t e -------------
2529 // -- rax : value
2530 // -- rcx : name
2531 // -- rdx : receiver
2532 // -- rsp[0] : return address
2533 // -----------------------------------
2534 {
2535 FrameScope scope(masm, StackFrame::INTERNAL);
2536
2537 // Save value register, so we can restore it later.
2538 __ push(rax);
2539
2540 if (!setter.is_null()) {
2541 // Call the JavaScript setter with receiver and value on the stack.
2542 __ push(rdx);
2543 __ push(rax);
2544 ParameterCount actual(1);
2545 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2546 CALL_AS_METHOD);
2547 } else {
2548 // If we generate a global code snippet for deoptimization only, remember
2549 // the place to continue after deoptimization.
2550 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2551 }
2552
2553 // We have to return the passed value, not the return value of the setter.
2554 __ pop(rax);
2555
2556 // Restore context register.
2557 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2558 }
2559 __ ret(0);
2560}
2561
2562
2563#undef __
2564#define __ ACCESS_MASM(masm())
2565
2566
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002567Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002568 Handle<String> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002569 Handle<JSObject> receiver,
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002570 Handle<JSObject> holder,
2571 Handle<JSFunction> setter) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002572 // ----------- S t a t e -------------
2573 // -- rax : value
2574 // -- rcx : name
2575 // -- rdx : receiver
2576 // -- rsp[0] : return address
2577 // -----------------------------------
2578 Label miss;
2579
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002580 // Check that the maps haven't changed.
2581 __ JumpIfSmi(rdx, &miss);
2582 CheckPrototypes(receiver, rdx, holder, rbx, r8, rdi, name, &miss);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002583
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002584 GenerateStoreViaSetter(masm(), setter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002585
2586 __ bind(&miss);
2587 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2588 __ Jump(ic, RelocInfo::CODE_TARGET);
2589
2590 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002591 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002592}
2593
2594
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002595Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2596 Handle<JSObject> receiver,
2597 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002598 // ----------- S t a t e -------------
2599 // -- rax : value
2600 // -- rcx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002601 // -- rdx : receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002602 // -- rsp[0] : return address
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002603 // -----------------------------------
2604 Label miss;
2605
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002606 // Check that the map of the object hasn't changed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002607 __ CheckMap(rdx, Handle<Map>(receiver->map()), &miss,
2608 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002609
2610 // Perform global security token check if needed.
2611 if (receiver->IsJSGlobalProxy()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002612 __ CheckAccessGlobalProxy(rdx, rbx, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002613 }
2614
2615 // Stub never generated for non-global objects that require access
2616 // checks.
2617 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2618
2619 __ pop(rbx); // remove the return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002620 __ push(rdx); // receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002621 __ push(rcx); // name
2622 __ push(rax); // value
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002623 __ Push(Smi::FromInt(strict_mode_));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002624 __ push(rbx); // restore return address
2625
2626 // Do tail-call to the runtime system.
2627 ExternalReference store_ic_property =
lrn@chromium.org7516f052011-03-30 08:52:27 +00002628 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002629 __ TailCallExternalReference(store_ic_property, 4, 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002630
2631 // Handle store cache miss.
2632 __ bind(&miss);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002633 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002634 __ Jump(ic, RelocInfo::CODE_TARGET);
2635
2636 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002637 return GetCode(Code::INTERCEPTOR, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002638}
2639
2640
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002641Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2642 Handle<GlobalObject> object,
2643 Handle<JSGlobalPropertyCell> cell,
2644 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002645 // ----------- S t a t e -------------
2646 // -- rax : value
2647 // -- rcx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002648 // -- rdx : receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002649 // -- rsp[0] : return address
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002650 // -----------------------------------
2651 Label miss;
2652
2653 // Check that the map of the global has not changed.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002654 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002655 Handle<Map>(object->map()));
2656 __ j(not_equal, &miss);
2657
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002658 // Compute the cell operand to use.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002659 __ Move(rbx, cell);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002660 Operand cell_operand = FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset);
2661
ager@chromium.org378b34e2011-01-28 08:04:38 +00002662 // Check that the value in the cell is not the hole. If it is, this
2663 // cell could have been deleted and reintroducing the global needs
2664 // to update the property details in the property dictionary of the
2665 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002666 __ CompareRoot(cell_operand, Heap::kTheHoleValueRootIndex);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002667 __ j(equal, &miss);
2668
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002669 // Store the value in the cell.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002670 __ movq(cell_operand, rax);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002671 // Cells are always rescanned, so no write barrier here.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002672
2673 // Return the value (register rax).
lrn@chromium.org7516f052011-03-30 08:52:27 +00002674 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002675 __ IncrementCounter(counters->named_store_global_inline(), 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002676 __ ret(0);
2677
2678 // Handle store cache miss.
2679 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002680 __ IncrementCounter(counters->named_store_global_inline_miss(), 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002681 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002682 __ Jump(ic, RelocInfo::CODE_TARGET);
2683
2684 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002685 return GetCode(Code::NORMAL, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002686}
2687
2688
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002689Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002690 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002691 Handle<Map> transition,
2692 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002693 // ----------- S t a t e -------------
2694 // -- rax : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002695 // -- rcx : key
2696 // -- rdx : receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002697 // -- rsp[0] : return address
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002698 // -----------------------------------
2699 Label miss;
2700
lrn@chromium.org7516f052011-03-30 08:52:27 +00002701 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002702 __ IncrementCounter(counters->keyed_store_field(), 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002703
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002704 // Check that the name has not changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002705 __ Cmp(rcx, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002706 __ j(not_equal, &miss);
2707
ager@chromium.org5c838252010-02-19 08:53:10 +00002708 // Generate store field code. Preserves receiver and name on jump to miss.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002709 GenerateStoreField(masm(),
2710 object,
2711 index,
2712 transition,
2713 name,
2714 rdx, rcx, rbx, rdi,
2715 &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002716
2717 // Handle store cache miss.
2718 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002719 __ DecrementCounter(counters->keyed_store_field(), 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002720 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002721 __ Jump(ic, RelocInfo::CODE_TARGET);
2722
2723 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002724 return GetCode(transition.is_null()
2725 ? Code::FIELD
2726 : Code::MAP_TRANSITION, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002727}
2728
2729
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002730Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
2731 Handle<Map> receiver_map) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002732 // ----------- S t a t e -------------
2733 // -- rax : value
2734 // -- rcx : key
2735 // -- rdx : receiver
2736 // -- rsp[0] : return address
2737 // -----------------------------------
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002738
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002739 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002740 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002741 Handle<Code> stub =
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002742 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002743
2744 __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002745
2746 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
2747 __ jmp(ic, RelocInfo::CODE_TARGET);
2748
2749 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002750 return GetCode(Code::NORMAL, factory()->empty_string());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002751}
2752
2753
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002754Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2755 MapHandleList* receiver_maps,
2756 CodeHandleList* handler_stubs,
2757 MapHandleList* transitioned_maps) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002758 // ----------- S t a t e -------------
2759 // -- rax : value
2760 // -- rcx : key
2761 // -- rdx : receiver
2762 // -- rsp[0] : return address
2763 // -----------------------------------
2764 Label miss;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002765 __ JumpIfSmi(rdx, &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002766
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002767 __ movq(rdi, FieldOperand(rdx, HeapObject::kMapOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002768 int receiver_count = receiver_maps->length();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002769 for (int i = 0; i < receiver_count; ++i) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002770 // Check map and tail call if there's a match
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002771 __ Cmp(rdi, receiver_maps->at(i));
2772 if (transitioned_maps->at(i).is_null()) {
2773 __ j(equal, handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002774 } else {
2775 Label next_map;
2776 __ j(not_equal, &next_map, Label::kNear);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002777 __ movq(rbx, transitioned_maps->at(i), RelocInfo::EMBEDDED_OBJECT);
2778 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002779 __ bind(&next_map);
2780 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002781 }
2782
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002783 __ bind(&miss);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002784 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002785 __ jmp(ic, RelocInfo::CODE_TARGET);
2786
2787 // Return the generated code.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002788 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002789}
2790
2791
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002792Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
2793 Handle<String> name,
2794 Handle<JSObject> object,
2795 Handle<JSObject> last,
2796 Handle<GlobalObject> global) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002797 // ----------- S t a t e -------------
2798 // -- rax : receiver
2799 // -- rcx : name
2800 // -- rsp[0] : return address
2801 // -----------------------------------
2802 Label miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002803
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002804 // Check that receiver is not a smi.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002805 __ JumpIfSmi(rax, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002806
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002807 // Check the maps of the full prototype chain. Also check that
2808 // global property cells up to (but not including) the last object
2809 // in the prototype chain are empty.
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002810 Register scratch = rdx;
2811 Register result =
2812 CheckPrototypes(object, rax, last, rbx, scratch, rdi, name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002813
2814 // If the last object in the prototype chain is a global object,
2815 // check that the global property cell is empty.
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002816 if (!global.is_null()) {
2817 GenerateCheckPropertyCell(masm(), global, name, scratch, &miss);
2818 }
2819
2820 if (!last->HasFastProperties()) {
2821 __ movq(scratch, FieldOperand(result, HeapObject::kMapOffset));
2822 __ movq(scratch, FieldOperand(scratch, Map::kPrototypeOffset));
2823 __ Cmp(scratch, isolate()->factory()->null_value());
2824 __ j(not_equal, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002825 }
2826
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002827 // Return undefined if maps of the full prototype chain are still the
2828 // same and no global property with this name contains a value.
2829 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2830 __ ret(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002831
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002832 __ bind(&miss);
2833 GenerateLoadMiss(masm(), Code::LOAD_IC);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002834
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002835 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002836 return GetCode(Code::NONEXISTENT, factory()->empty_string());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002837}
2838
2839
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002840Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2841 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002842 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002843 Handle<String> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002844 // ----------- S t a t e -------------
2845 // -- rax : receiver
2846 // -- rcx : name
2847 // -- rsp[0] : return address
2848 // -----------------------------------
2849 Label miss;
2850
2851 GenerateLoadField(object, holder, rax, rbx, rdx, rdi, index, name, &miss);
2852 __ bind(&miss);
2853 GenerateLoadMiss(masm(), Code::LOAD_IC);
2854
2855 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002856 return GetCode(Code::FIELD, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002857}
2858
2859
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002860Handle<Code> LoadStubCompiler::CompileLoadCallback(
2861 Handle<String> name,
2862 Handle<JSObject> object,
2863 Handle<JSObject> holder,
2864 Handle<AccessorInfo> callback) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002865 // ----------- S t a t e -------------
2866 // -- rax : receiver
2867 // -- rcx : name
2868 // -- rsp[0] : return address
2869 // -----------------------------------
2870 Label miss;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00002871 GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, rdi, r8, callback,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002872 name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002873 __ bind(&miss);
2874 GenerateLoadMiss(masm(), Code::LOAD_IC);
2875
2876 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002877 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002878}
2879
2880
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002881#undef __
2882#define __ ACCESS_MASM(masm)
2883
2884
2885void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2886 Handle<JSFunction> getter) {
2887 // ----------- S t a t e -------------
2888 // -- rax : receiver
2889 // -- rcx : name
2890 // -- rsp[0] : return address
2891 // -----------------------------------
2892 {
2893 FrameScope scope(masm, StackFrame::INTERNAL);
2894
2895 if (!getter.is_null()) {
2896 // Call the JavaScript getter with the receiver on the stack.
2897 __ push(rax);
2898 ParameterCount actual(0);
2899 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
2900 CALL_AS_METHOD);
2901 } else {
2902 // If we generate a global code snippet for deoptimization only, remember
2903 // the place to continue after deoptimization.
2904 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2905 }
2906
2907 // Restore context register.
2908 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2909 }
2910 __ ret(0);
2911}
2912
2913
2914#undef __
2915#define __ ACCESS_MASM(masm())
2916
2917
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002918Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
2919 Handle<String> name,
2920 Handle<JSObject> receiver,
2921 Handle<JSObject> holder,
2922 Handle<JSFunction> getter) {
2923 // ----------- S t a t e -------------
2924 // -- rax : receiver
2925 // -- rcx : name
2926 // -- rsp[0] : return address
2927 // -----------------------------------
2928 Label miss;
2929
2930 // Check that the maps haven't changed.
2931 __ JumpIfSmi(rax, &miss);
2932 CheckPrototypes(receiver, rax, holder, rbx, rdx, rdi, name, &miss);
2933
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002934 GenerateLoadViaGetter(masm(), getter),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002935
2936 __ bind(&miss);
2937 GenerateLoadMiss(masm(), Code::LOAD_IC);
2938
2939 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002940 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002941}
2942
2943
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002944Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2945 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002946 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002947 Handle<String> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002948 // ----------- S t a t e -------------
2949 // -- rax : receiver
2950 // -- rcx : name
2951 // -- rsp[0] : return address
2952 // -----------------------------------
2953 Label miss;
2954
2955 GenerateLoadConstant(object, holder, rax, rbx, rdx, rdi, value, name, &miss);
2956 __ bind(&miss);
2957 GenerateLoadMiss(masm(), Code::LOAD_IC);
2958
2959 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002960 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002961}
2962
2963
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002964Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> receiver,
2965 Handle<JSObject> holder,
2966 Handle<String> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002967 // ----------- S t a t e -------------
2968 // -- rax : receiver
2969 // -- rcx : name
2970 // -- rsp[0] : return address
2971 // -----------------------------------
2972 Label miss;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002973 LookupResult lookup(isolate());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002974 LookupPostInterceptor(holder, name, &lookup);
2975
2976 // TODO(368): Compile in the whole chain: all the interceptors in
2977 // prototypes and ultimate answer.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002978 GenerateLoadInterceptor(receiver, holder, &lookup, rax, rcx, rdx, rbx, rdi,
2979 name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002980 __ bind(&miss);
2981 GenerateLoadMiss(masm(), Code::LOAD_IC);
2982
2983 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002984 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002985}
2986
2987
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002988Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2989 Handle<JSObject> object,
2990 Handle<GlobalObject> holder,
2991 Handle<JSGlobalPropertyCell> cell,
2992 Handle<String> name,
2993 bool is_dont_delete) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002994 // ----------- S t a t e -------------
2995 // -- rax : receiver
2996 // -- rcx : name
2997 // -- rsp[0] : return address
2998 // -----------------------------------
2999 Label miss;
3000
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003001 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003002 __ JumpIfSmi(rax, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003003 CheckPrototypes(object, rax, holder, rbx, rdx, rdi, name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003004
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003005 // Get the value from the cell.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003006 __ Move(rbx, cell);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003007 __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset));
whesse@chromium.orge90029b2010-08-02 11:52:17 +00003008
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003009 // Check for deleted property if property can actually be deleted.
3010 if (!is_dont_delete) {
3011 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
3012 __ j(equal, &miss);
3013 } else if (FLAG_debug_code) {
3014 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
3015 __ Check(not_equal, "DontDelete cells can't contain the hole");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003016 }
3017
lrn@chromium.org7516f052011-03-30 08:52:27 +00003018 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003019 __ IncrementCounter(counters->named_load_global_stub(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003020 __ movq(rax, rbx);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003021 __ ret(0);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003022
3023 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003024 __ IncrementCounter(counters->named_load_global_stub_miss(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003025 GenerateLoadMiss(masm(), Code::LOAD_IC);
3026
3027 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003028 return GetCode(Code::NORMAL, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003029}
3030
3031
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003032Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
3033 Handle<JSObject> receiver,
3034 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003035 PropertyIndex index) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003036 // ----------- S t a t e -------------
3037 // -- rax : key
3038 // -- rdx : receiver
3039 // -- rsp[0] : return address
3040 // -----------------------------------
3041 Label miss;
3042
lrn@chromium.org7516f052011-03-30 08:52:27 +00003043 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003044 __ IncrementCounter(counters->keyed_load_field(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003045
3046 // Check that the name has not changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003047 __ Cmp(rax, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003048 __ j(not_equal, &miss);
3049
3050 GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss);
3051
3052 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003053 __ DecrementCounter(counters->keyed_load_field(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003054 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3055
3056 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003057 return GetCode(Code::FIELD, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003058}
3059
3060
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003061Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
3062 Handle<String> name,
3063 Handle<JSObject> receiver,
3064 Handle<JSObject> holder,
3065 Handle<AccessorInfo> callback) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003066 // ----------- S t a t e -------------
3067 // -- rax : key
3068 // -- rdx : receiver
3069 // -- rsp[0] : return address
3070 // -----------------------------------
3071 Label miss;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003072 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003073 __ IncrementCounter(counters->keyed_load_callback(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003074
3075 // Check that the name has not changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003076 __ Cmp(rax, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003077 __ j(not_equal, &miss);
3078
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003079 GenerateLoadCallback(receiver, holder, rdx, rax, rbx, rcx, rdi, r8, callback,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003080 name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003081 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003082 __ DecrementCounter(counters->keyed_load_callback(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003083 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3084
3085 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003086 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003087}
3088
3089
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003090Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
3091 Handle<String> name,
3092 Handle<JSObject> receiver,
3093 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003094 Handle<JSFunction> value) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003095 // ----------- S t a t e -------------
3096 // -- rax : key
3097 // -- rdx : receiver
3098 // -- rsp[0] : return address
3099 // -----------------------------------
3100 Label miss;
3101
lrn@chromium.org7516f052011-03-30 08:52:27 +00003102 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003103 __ IncrementCounter(counters->keyed_load_constant_function(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003104
3105 // Check that the name has not changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003106 __ Cmp(rax, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003107 __ j(not_equal, &miss);
3108
3109 GenerateLoadConstant(receiver, holder, rdx, rbx, rcx, rdi,
3110 value, name, &miss);
3111 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003112 __ DecrementCounter(counters->keyed_load_constant_function(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003113 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3114
3115 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003116 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003117}
3118
3119
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003120Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
3121 Handle<JSObject> receiver,
3122 Handle<JSObject> holder,
3123 Handle<String> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003124 // ----------- S t a t e -------------
3125 // -- rax : key
3126 // -- rdx : receiver
3127 // -- rsp[0] : return address
3128 // -----------------------------------
3129 Label miss;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003130 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003131 __ IncrementCounter(counters->keyed_load_interceptor(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003132
3133 // Check that the name has not changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003134 __ Cmp(rax, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003135 __ j(not_equal, &miss);
3136
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003137 LookupResult lookup(isolate());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003138 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003139 GenerateLoadInterceptor(receiver, holder, &lookup, rdx, rax, rcx, rbx, rdi,
3140 name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003141 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003142 __ DecrementCounter(counters->keyed_load_interceptor(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003143 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3144
3145 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003146 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003147}
3148
3149
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003150Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3151 Handle<Map> receiver_map) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003152 // ----------- S t a t e -------------
3153 // -- rax : key
3154 // -- rdx : receiver
3155 // -- rsp[0] : return address
3156 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003157 ElementsKind elements_kind = receiver_map->elements_kind();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003158 if (receiver_map->has_fast_elements() ||
3159 receiver_map->has_external_array_elements()) {
3160 Handle<Code> stub = KeyedLoadFastElementStub(
3161 receiver_map->instance_type() == JS_ARRAY_TYPE,
3162 elements_kind).GetCode();
3163 __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK);
3164 } else {
3165 Handle<Code> stub =
3166 KeyedLoadDictionaryElementStub().GetCode();
3167 __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK);
3168 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003169
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003170 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003171
3172 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003173 return GetCode(Code::NORMAL, factory()->empty_string());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003174}
3175
3176
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003177Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3178 MapHandleList* receiver_maps,
3179 CodeHandleList* handler_ics) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003180 // ----------- S t a t e -------------
3181 // -- rax : key
3182 // -- rdx : receiver
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003183 // -- rsp[0] : return address
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003184 // -----------------------------------
3185 Label miss;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003186 __ JumpIfSmi(rdx, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003187
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003188 Register map_reg = rbx;
3189 __ movq(map_reg, FieldOperand(rdx, HeapObject::kMapOffset));
3190 int receiver_count = receiver_maps->length();
3191 for (int current = 0; current < receiver_count; ++current) {
3192 // Check map and tail call if there's a match
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003193 __ Cmp(map_reg, receiver_maps->at(current));
3194 __ j(equal, handler_ics->at(current), RelocInfo::CODE_TARGET);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003195 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003196
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003197 __ bind(&miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003198 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3199
3200 // Return the generated code.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003201 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003202}
3203
3204
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003205// Specialized stub for constructing objects from functions which only have only
3206// simple assignments of the form this.x = ...; in their body.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003207Handle<Code> ConstructStubCompiler::CompileConstructStub(
3208 Handle<JSFunction> function) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003209 // ----------- S t a t e -------------
3210 // -- rax : argc
3211 // -- rdi : constructor
3212 // -- rsp[0] : return address
3213 // -- rsp[4] : last argument
3214 // -----------------------------------
3215 Label generic_stub_call;
3216
3217 // Use r8 for holding undefined which is used in several places below.
lrn@chromium.org7516f052011-03-30 08:52:27 +00003218 __ Move(r8, factory()->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003219
3220#ifdef ENABLE_DEBUGGER_SUPPORT
3221 // Check to see whether there are any break points in the function code. If
3222 // there are jump to the generic constructor stub which calls the actual
3223 // code for the function thereby hitting the break points.
3224 __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
3225 __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kDebugInfoOffset));
3226 __ cmpq(rbx, r8);
3227 __ j(not_equal, &generic_stub_call);
3228#endif
3229
3230 // Load the initial map and verify that it is in fact a map.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003231 // rdi: constructor
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003232 __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
3233 // Will both indicate a NULL and a Smi.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003234 STATIC_ASSERT(kSmiTag == 0);
ager@chromium.org4af710e2009-09-15 12:20:11 +00003235 __ JumpIfSmi(rbx, &generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003236 __ CmpObjectType(rbx, MAP_TYPE, rcx);
3237 __ j(not_equal, &generic_stub_call);
3238
3239#ifdef DEBUG
3240 // Cannot construct functions this way.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003241 // rbx: initial map
3242 __ CmpInstanceType(rbx, JS_FUNCTION_TYPE);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003243 __ Check(not_equal, "Function constructed by construct stub.");
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003244#endif
3245
3246 // Now allocate the JSObject in new space.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003247 // rbx: initial map
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003248 ASSERT(function->has_initial_map());
3249 int instance_size = function->initial_map()->instance_size();
3250#ifdef DEBUG
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003251 __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset));
3252 __ shl(rcx, Immediate(kPointerSizeLog2));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003253 __ cmpq(rcx, Immediate(instance_size));
3254 __ Check(equal, "Instance size of initial map changed.");
3255#endif
3256 __ AllocateInNewSpace(instance_size, rdx, rcx, no_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003257 &generic_stub_call, NO_ALLOCATION_FLAGS);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003258
3259 // Allocated the JSObject, now initialize the fields and add the heap tag.
3260 // rbx: initial map
3261 // rdx: JSObject (untagged)
3262 __ movq(Operand(rdx, JSObject::kMapOffset), rbx);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003263 __ Move(rbx, factory()->empty_fixed_array());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003264 __ movq(Operand(rdx, JSObject::kPropertiesOffset), rbx);
3265 __ movq(Operand(rdx, JSObject::kElementsOffset), rbx);
3266
3267 // rax: argc
3268 // rdx: JSObject (untagged)
3269 // Load the address of the first in-object property into r9.
3270 __ lea(r9, Operand(rdx, JSObject::kHeaderSize));
3271 // Calculate the location of the first argument. The stack contains only the
3272 // return address on top of the argc arguments.
3273 __ lea(rcx, Operand(rsp, rax, times_pointer_size, 0));
3274
3275 // rax: argc
3276 // rcx: first argument
3277 // rdx: JSObject (untagged)
3278 // r8: undefined
3279 // r9: first in-object property of the JSObject
3280 // Fill the initialized properties with a constant value or a passed argument
3281 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003282 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003283 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3284 if (shared->IsThisPropertyAssignmentArgument(i)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003285 // Check if the argument assigned to the property is actually passed.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003286 // If argument is not passed the property is set to undefined,
3287 // otherwise find it on the stack.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003288 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003289 __ movq(rbx, r8);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003290 __ cmpq(rax, Immediate(arg_number));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003291 __ cmovq(above, rbx, Operand(rcx, arg_number * -kPointerSize));
3292 // Store value in the property.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003293 __ movq(Operand(r9, i * kPointerSize), rbx);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003294 } else {
3295 // Set the property to the constant value.
3296 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3297 __ Move(Operand(r9, i * kPointerSize), constant);
3298 }
3299 }
3300
3301 // Fill the unused in-object property fields with undefined.
3302 for (int i = shared->this_property_assignments_count();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00003303 i < function->initial_map()->inobject_properties();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003304 i++) {
3305 __ movq(Operand(r9, i * kPointerSize), r8);
3306 }
3307
3308 // rax: argc
3309 // rdx: JSObject (untagged)
3310 // Move argc to rbx and the JSObject to return to rax and tag it.
3311 __ movq(rbx, rax);
3312 __ movq(rax, rdx);
3313 __ or_(rax, Immediate(kHeapObjectTag));
3314
3315 // rax: JSObject
3316 // rbx: argc
3317 // Remove caller arguments and receiver from the stack and return.
3318 __ pop(rcx);
3319 __ lea(rsp, Operand(rsp, rbx, times_pointer_size, 1 * kPointerSize));
3320 __ push(rcx);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003321 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003322 __ IncrementCounter(counters->constructed_objects(), 1);
3323 __ IncrementCounter(counters->constructed_objects_stub(), 1);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003324 __ ret(0);
3325
3326 // Jump to the generic stub in case the specialized code cannot handle the
3327 // construction.
3328 __ bind(&generic_stub_call);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003329 Handle<Code> code = isolate()->builtins()->JSConstructStubGeneric();
3330 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003331
3332 // Return the generated code.
3333 return GetCode();
3334}
3335
3336
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003337#undef __
3338#define __ ACCESS_MASM(masm)
3339
3340
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003341void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3342 MacroAssembler* masm) {
3343 // ----------- S t a t e -------------
3344 // -- rax : key
3345 // -- rdx : receiver
3346 // -- rsp[0] : return address
3347 // -----------------------------------
3348 Label slow, miss_force_generic;
3349
3350 // This stub is meant to be tail-jumped to, the receiver must already
3351 // have been verified by the caller to not be a smi.
3352
3353 __ JumpIfNotSmi(rax, &miss_force_generic);
3354 __ SmiToInteger32(rbx, rax);
3355 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
3356
3357 // Check whether the elements is a number dictionary.
3358 // rdx: receiver
3359 // rax: key
3360 // rbx: key as untagged int32
3361 // rcx: elements
3362 __ LoadFromNumberDictionary(&slow, rcx, rax, rbx, r9, rdi, rax);
3363 __ ret(0);
3364
3365 __ bind(&slow);
3366 // ----------- S t a t e -------------
3367 // -- rax : key
3368 // -- rdx : receiver
3369 // -- rsp[0] : return address
3370 // -----------------------------------
3371 Handle<Code> slow_ic =
3372 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3373 __ jmp(slow_ic, RelocInfo::CODE_TARGET);
3374
3375 __ bind(&miss_force_generic);
3376 // ----------- S t a t e -------------
3377 // -- rax : key
3378 // -- rdx : receiver
3379 // -- rsp[0] : return address
3380 // -----------------------------------
3381 Handle<Code> miss_ic =
3382 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3383 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
3384}
3385
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003386
3387static void GenerateSmiKeyCheck(MacroAssembler* masm,
3388 Register key,
3389 Register scratch,
3390 XMMRegister xmm_scratch0,
3391 XMMRegister xmm_scratch1,
3392 Label* fail) {
3393 // Check that key is a smi or a heap number containing a smi and branch
3394 // if the check fails.
3395 Label key_ok;
3396 __ JumpIfSmi(key, &key_ok);
3397 __ CheckMap(key,
3398 masm->isolate()->factory()->heap_number_map(),
3399 fail,
3400 DONT_DO_SMI_CHECK);
3401 __ movsd(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset));
3402 __ cvttsd2si(scratch, xmm_scratch0);
3403 __ cvtlsi2sd(xmm_scratch1, scratch);
3404 __ ucomisd(xmm_scratch1, xmm_scratch0);
3405 __ j(not_equal, fail);
3406 __ j(parity_even, fail); // NaN.
3407 __ Integer32ToSmi(key, scratch);
3408 __ bind(&key_ok);
3409}
3410
3411
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003412void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3413 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003414 ElementsKind elements_kind) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003415 // ----------- S t a t e -------------
3416 // -- rax : value
3417 // -- rcx : key
3418 // -- rdx : receiver
3419 // -- rsp[0] : return address
3420 // -----------------------------------
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003421 Label slow, miss_force_generic;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003422
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003423 // This stub is meant to be tail-jumped to, the receiver must already
3424 // have been verified by the caller to not be a smi.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003425
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003426 // Check that the key is a smi or a heap number convertible to a smi.
3427 GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003428
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003429 // Check that the index is in range.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003430 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
danno@chromium.orgb6451162011-08-17 14:33:23 +00003431 __ SmiToInteger32(rdi, rcx); // Untag the index.
3432 __ cmpq(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003433 // Unsigned comparison catches both negative and too-large values.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003434 __ j(above_equal, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003435
3436 // Handle both smis and HeapNumbers in the fast path. Go to the
3437 // runtime for all other kinds of values.
3438 // rax: value
3439 // rcx: key (a smi)
3440 // rdx: receiver (a JSObject)
3441 // rbx: elements array
danno@chromium.orgb6451162011-08-17 14:33:23 +00003442 // rdi: untagged key
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003443 Label check_heap_number;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003444 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003445 // Float to pixel conversion is only implemented in the runtime for now.
3446 __ JumpIfNotSmi(rax, &slow);
3447 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003448 __ JumpIfNotSmi(rax, &check_heap_number, Label::kNear);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003449 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003450 // No more branches to slow case on this path. Key and receiver not needed.
3451 __ SmiToInteger32(rdx, rax);
3452 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
3453 // rbx: base pointer of external storage
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003454 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003455 case EXTERNAL_PIXEL_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003456 { // Clamp the value to [0..255].
3457 Label done;
3458 __ testl(rdx, Immediate(0xFFFFFF00));
3459 __ j(zero, &done, Label::kNear);
3460 __ setcc(negative, rdx); // 1 if negative, 0 if positive.
3461 __ decb(rdx); // 0 if negative, 255 if positive.
3462 __ bind(&done);
3463 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003464 __ movb(Operand(rbx, rdi, times_1, 0), rdx);
3465 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003466 case EXTERNAL_BYTE_ELEMENTS:
3467 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003468 __ movb(Operand(rbx, rdi, times_1, 0), rdx);
3469 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003470 case EXTERNAL_SHORT_ELEMENTS:
3471 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003472 __ movw(Operand(rbx, rdi, times_2, 0), rdx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003473 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003474 case EXTERNAL_INT_ELEMENTS:
3475 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003476 __ movl(Operand(rbx, rdi, times_4, 0), rdx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003477 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003478 case EXTERNAL_FLOAT_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003479 // Need to perform int-to-float conversion.
3480 __ cvtlsi2ss(xmm0, rdx);
danno@chromium.orgb6451162011-08-17 14:33:23 +00003481 __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003482 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003483 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003484 // Need to perform int-to-float conversion.
3485 __ cvtlsi2sd(xmm0, rdx);
danno@chromium.orgb6451162011-08-17 14:33:23 +00003486 __ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003487 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003488 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003489 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003490 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003491 case FAST_HOLEY_ELEMENTS:
3492 case FAST_HOLEY_SMI_ELEMENTS:
3493 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003494 case DICTIONARY_ELEMENTS:
3495 case NON_STRICT_ARGUMENTS_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003496 UNREACHABLE();
3497 break;
3498 }
3499 __ ret(0);
3500
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003501 // TODO(danno): handle heap number -> pixel array conversion
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003502 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003503 __ bind(&check_heap_number);
3504 // rax: value
3505 // rcx: key (a smi)
3506 // rdx: receiver (a JSObject)
3507 // rbx: elements array
danno@chromium.orgb6451162011-08-17 14:33:23 +00003508 // rdi: untagged key
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003509 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister);
3510 __ j(not_equal, &slow);
3511 // No more branches to slow case on this path.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003512
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003513 // The WebGL specification leaves the behavior of storing NaN and
3514 // +/-Infinity into integer arrays basically undefined. For more
3515 // reproducible behavior, convert these to zero.
3516 __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
3517 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
danno@chromium.orgb6451162011-08-17 14:33:23 +00003518 // rdi: untagged index
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003519 // rbx: base pointer of external storage
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003520 // top of FPU stack: value
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003521 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003522 __ cvtsd2ss(xmm0, xmm0);
danno@chromium.orgb6451162011-08-17 14:33:23 +00003523 __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003524 __ ret(0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003525 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00003526 __ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003527 __ ret(0);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003528 } else {
3529 // Perform float-to-int conversion with truncation (round-to-zero)
3530 // behavior.
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003531 // Fast path: use machine instruction to convert to int64. If that
3532 // fails (out-of-range), go into the runtime.
3533 __ cvttsd2siq(r8, xmm0);
3534 __ Set(kScratchRegister, V8_UINT64_C(0x8000000000000000));
3535 __ cmpq(r8, kScratchRegister);
3536 __ j(equal, &slow);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003537
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003538 // rdx: value (converted to an untagged integer)
3539 // rdi: untagged index
3540 // rbx: base pointer of external storage
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003541 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003542 case EXTERNAL_BYTE_ELEMENTS:
3543 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003544 __ movb(Operand(rbx, rdi, times_1, 0), r8);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003545 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003546 case EXTERNAL_SHORT_ELEMENTS:
3547 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003548 __ movw(Operand(rbx, rdi, times_2, 0), r8);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003549 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003550 case EXTERNAL_INT_ELEMENTS:
3551 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003552 __ movl(Operand(rbx, rdi, times_4, 0), r8);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003553 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003554 case EXTERNAL_PIXEL_ELEMENTS:
3555 case EXTERNAL_FLOAT_ELEMENTS:
3556 case EXTERNAL_DOUBLE_ELEMENTS:
3557 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003558 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003559 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003560 case FAST_HOLEY_ELEMENTS:
3561 case FAST_HOLEY_SMI_ELEMENTS:
3562 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003563 case DICTIONARY_ELEMENTS:
3564 case NON_STRICT_ARGUMENTS_ELEMENTS:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003565 UNREACHABLE();
3566 break;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003567 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003568 __ ret(0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003569 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003570 }
3571
3572 // Slow case: call runtime.
3573 __ bind(&slow);
3574
3575 // ----------- S t a t e -------------
3576 // -- rax : value
3577 // -- rcx : key
3578 // -- rdx : receiver
3579 // -- rsp[0] : return address
3580 // -----------------------------------
3581
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003582 Handle<Code> ic = masm->isolate()->builtins()->KeyedStoreIC_Slow();
3583 __ jmp(ic, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003584
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003585 // Miss case: call runtime.
3586 __ bind(&miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003587
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003588 // ----------- S t a t e -------------
3589 // -- rax : value
3590 // -- rcx : key
3591 // -- rdx : receiver
3592 // -- rsp[0] : return address
3593 // -----------------------------------
3594
3595 Handle<Code> miss_ic =
3596 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3597 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003598}
3599
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003600
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003601void KeyedStoreStubCompiler::GenerateStoreFastElement(
3602 MacroAssembler* masm,
3603 bool is_js_array,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003604 ElementsKind elements_kind,
3605 KeyedAccessGrowMode grow_mode) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003606 // ----------- S t a t e -------------
3607 // -- rax : value
3608 // -- rcx : key
3609 // -- rdx : receiver
3610 // -- rsp[0] : return address
3611 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003612 Label miss_force_generic, transition_elements_kind, finish_store, grow;
3613 Label check_capacity, slow;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003614
3615 // This stub is meant to be tail-jumped to, the receiver must already
3616 // have been verified by the caller to not be a smi.
3617
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003618 // Check that the key is a smi or a heap number convertible to a smi.
3619 GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003620
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003621 if (IsFastSmiElementsKind(elements_kind)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003622 __ JumpIfNotSmi(rax, &transition_elements_kind);
3623 }
3624
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003625 // Get the elements array and make sure it is a fast element array, not 'cow'.
3626 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003627 // Check that the key is within bounds.
3628 if (is_js_array) {
3629 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003630 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
3631 __ j(above_equal, &grow);
3632 } else {
3633 __ j(above_equal, &miss_force_generic);
3634 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003635 } else {
3636 __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
3637 __ j(above_equal, &miss_force_generic);
3638 }
3639
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003640 __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset),
3641 Heap::kFixedArrayMapRootIndex);
3642 __ j(not_equal, &miss_force_generic);
3643
3644 __ bind(&finish_store);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003645 if (IsFastSmiElementsKind(elements_kind)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003646 __ SmiToInteger32(rcx, rcx);
3647 __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize),
3648 rax);
3649 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003650 // Do the store and update the write barrier.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003651 ASSERT(IsFastObjectElementsKind(elements_kind));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003652 __ SmiToInteger32(rcx, rcx);
3653 __ lea(rcx,
3654 FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize));
3655 __ movq(Operand(rcx, 0), rax);
3656 // Make sure to preserve the value in register rax.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003657 __ movq(rbx, rax);
3658 __ RecordWrite(rdi, rcx, rbx, kDontSaveFPRegs);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003659 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003660
3661 // Done.
3662 __ ret(0);
3663
3664 // Handle store cache miss.
3665 __ bind(&miss_force_generic);
3666 Handle<Code> ic_force_generic =
3667 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3668 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003669
3670 __ bind(&transition_elements_kind);
3671 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
3672 __ jmp(ic_miss, RelocInfo::CODE_TARGET);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003673
3674 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
3675 // Grow the array by a single element if possible.
3676 __ bind(&grow);
3677
3678 // Make sure the array is only growing by a single element, anything else
3679 // must be handled by the runtime. Flags are already set by previous
3680 // compare.
3681 __ j(not_equal, &miss_force_generic);
3682
3683 // Check for the empty array, and preallocate a small backing store if
3684 // possible.
3685 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
3686 __ CompareRoot(rdi, Heap::kEmptyFixedArrayRootIndex);
3687 __ j(not_equal, &check_capacity);
3688
3689 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
3690 __ AllocateInNewSpace(size, rdi, rbx, r8, &slow, TAG_OBJECT);
3691
3692 // rax: value
3693 // rcx: key
3694 // rdx: receiver
3695 // rdi: elements
3696 // Make sure that the backing store can hold additional elements.
3697 __ Move(FieldOperand(rdi, JSObject::kMapOffset),
3698 masm->isolate()->factory()->fixed_array_map());
3699 __ Move(FieldOperand(rdi, FixedArray::kLengthOffset),
3700 Smi::FromInt(JSArray::kPreallocatedArrayElements));
3701 __ LoadRoot(rbx, Heap::kTheHoleValueRootIndex);
3702 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3703 __ movq(FieldOperand(rdi, FixedArray::SizeFor(i)), rbx);
3704 }
3705
3706 // Store the element at index zero.
3707 __ movq(FieldOperand(rdi, FixedArray::SizeFor(0)), rax);
3708
3709 // Install the new backing store in the JSArray.
3710 __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi);
3711 __ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx,
3712 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3713
3714 // Increment the length of the array.
3715 __ Move(FieldOperand(rdx, JSArray::kLengthOffset), Smi::FromInt(1));
3716 __ ret(0);
3717
3718 __ bind(&check_capacity);
3719 // Check for cow elements, in general they are not handled by this stub.
3720 __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset),
3721 Heap::kFixedCOWArrayMapRootIndex);
3722 __ j(equal, &miss_force_generic);
3723
3724 // rax: value
3725 // rcx: key
3726 // rdx: receiver
3727 // rdi: elements
3728 // Make sure that the backing store can hold additional elements.
3729 __ cmpq(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
3730 __ j(above_equal, &slow);
3731
3732 // Grow the array and finish the store.
3733 __ SmiAddConstant(FieldOperand(rdx, JSArray::kLengthOffset),
3734 Smi::FromInt(1));
3735 __ jmp(&finish_store);
3736
3737 __ bind(&slow);
3738 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
3739 __ jmp(ic_slow, RelocInfo::CODE_TARGET);
3740 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003741}
3742
3743
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003744void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3745 MacroAssembler* masm,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003746 bool is_js_array,
3747 KeyedAccessGrowMode grow_mode) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003748 // ----------- S t a t e -------------
3749 // -- rax : value
3750 // -- rcx : key
3751 // -- rdx : receiver
3752 // -- rsp[0] : return address
3753 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003754 Label miss_force_generic, transition_elements_kind, finish_store;
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003755 Label grow, slow, check_capacity, restore_key_transition_elements_kind;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003756
3757 // This stub is meant to be tail-jumped to, the receiver must already
3758 // have been verified by the caller to not be a smi.
3759
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003760 // Check that the key is a smi or a heap number convertible to a smi.
3761 GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003762
3763 // Get the elements array.
3764 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
3765 __ AssertFastElements(rdi);
3766
3767 // Check that the key is within bounds.
3768 if (is_js_array) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003769 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
3770 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
3771 __ j(above_equal, &grow);
3772 } else {
3773 __ j(above_equal, &miss_force_generic);
3774 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003775 } else {
3776 __ SmiCompare(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003777 __ j(above_equal, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003778 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003779
3780 // Handle smi values specially
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003781 __ bind(&finish_store);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003782 __ SmiToInteger32(rcx, rcx);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003783 __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0,
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003784 &restore_key_transition_elements_kind);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003785 __ ret(0);
3786
3787 // Handle store cache miss, replacing the ic with the generic stub.
3788 __ bind(&miss_force_generic);
3789 Handle<Code> ic_force_generic =
3790 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3791 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003792
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003793 __ bind(&restore_key_transition_elements_kind);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003794 // Restore smi-tagging of rcx.
3795 __ Integer32ToSmi(rcx, rcx);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003796 __ bind(&transition_elements_kind);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003797 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
3798 __ jmp(ic_miss, RelocInfo::CODE_TARGET);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003799
3800 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
3801 // Grow the array by a single element if possible.
3802 __ bind(&grow);
3803
3804 // Make sure the array is only growing by a single element, anything else
3805 // must be handled by the runtime. Flags are already set by previous
3806 // compare.
3807 __ j(not_equal, &miss_force_generic);
3808
3809 // Transition on values that can't be stored in a FixedDoubleArray.
3810 Label value_is_smi;
3811 __ JumpIfSmi(rax, &value_is_smi);
3812 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
3813 Heap::kHeapNumberMapRootIndex);
3814 __ j(not_equal, &transition_elements_kind);
3815 __ bind(&value_is_smi);
3816
3817 // Check for the empty array, and preallocate a small backing store if
3818 // possible.
3819 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
3820 __ CompareRoot(rdi, Heap::kEmptyFixedArrayRootIndex);
3821 __ j(not_equal, &check_capacity);
3822
3823 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
3824 __ AllocateInNewSpace(size, rdi, rbx, r8, &slow, TAG_OBJECT);
3825
3826 // rax: value
3827 // rcx: key
3828 // rdx: receiver
3829 // rdi: elements
3830 // Initialize the new FixedDoubleArray. Leave elements unitialized for
3831 // efficiency, they are guaranteed to be initialized before use.
3832 __ Move(FieldOperand(rdi, JSObject::kMapOffset),
3833 masm->isolate()->factory()->fixed_double_array_map());
3834 __ Move(FieldOperand(rdi, FixedDoubleArray::kLengthOffset),
3835 Smi::FromInt(JSArray::kPreallocatedArrayElements));
3836
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003837 // Increment the length of the array.
3838 __ SmiToInteger32(rcx, rcx);
3839 __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0,
3840 &restore_key_transition_elements_kind);
3841
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00003842 __ movq(r8, BitCast<int64_t, uint64_t>(kHoleNanInt64), RelocInfo::NONE64);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003843 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
3844 __ movq(FieldOperand(rdi, FixedDoubleArray::OffsetOfElementAt(i)), r8);
3845 }
3846
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003847 // Install the new backing store in the JSArray.
3848 __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi);
3849 __ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx,
3850 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3851
3852 // Increment the length of the array.
3853 __ Move(FieldOperand(rdx, JSArray::kLengthOffset), Smi::FromInt(1));
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003854 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003855 __ ret(0);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003856
3857 __ bind(&check_capacity);
3858 // rax: value
3859 // rcx: key
3860 // rdx: receiver
3861 // rdi: elements
3862 // Make sure that the backing store can hold additional elements.
3863 __ cmpq(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset));
3864 __ j(above_equal, &slow);
3865
3866 // Grow the array and finish the store.
3867 __ SmiAddConstant(FieldOperand(rdx, JSArray::kLengthOffset),
3868 Smi::FromInt(1));
3869 __ jmp(&finish_store);
3870
3871 __ bind(&slow);
3872 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
3873 __ jmp(ic_slow, RelocInfo::CODE_TARGET);
3874 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003875}
3876
3877
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003878#undef __
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003879
3880} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003881
3882#endif // V8_TARGET_ARCH_X64