blob: df6b5d5fdae2968a6739b554b1a5b6fb1358d568 [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,
231 Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
232 // Load the global context from the global or builtins object.
233 __ movq(prototype,
234 FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
235 // Load the function from the global context.
236 __ movq(prototype, Operand(prototype, Context::SlotOffset(index)));
237 // Load the initial map. The global functions all have initial maps.
238 __ movq(prototype,
239 FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
240 // 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.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000252 __ Move(prototype, isolate->global());
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000253 __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)),
254 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(
258 JSFunction::cast(isolate->global_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,
353 int index) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000354 // Adjust for the number of properties stored in the holder.
355 index -= holder->map()->inobject_properties();
356 if (index < 0) {
357 // Get the property straight out of the holder.
358 int offset = holder->map()->instance_size() + (index * kPointerSize);
359 __ movq(dst, FieldOperand(src, offset));
360 } else {
361 // Calculate the offset into the properties array.
362 int offset = index * kPointerSize + FixedArray::kHeaderSize;
363 __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
364 __ movq(dst, FieldOperand(dst, offset));
365 }
366}
367
368
369static void PushInterceptorArguments(MacroAssembler* masm,
370 Register receiver,
371 Register holder,
372 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000373 Handle<JSObject> holder_obj) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000374 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000375 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
376 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
377 __ Move(kScratchRegister, interceptor);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000378 __ push(kScratchRegister);
379 __ push(receiver);
380 __ push(holder);
381 __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000382 __ PushAddress(ExternalReference::isolate_address());
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000383}
384
385
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000386static void CompileCallLoadPropertyWithInterceptor(
387 MacroAssembler* masm,
388 Register receiver,
389 Register holder,
390 Register name,
391 Handle<JSObject> holder_obj) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000392 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
393
394 ExternalReference ref =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000395 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
396 masm->isolate());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000397 __ Set(rax, 6);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000398 __ LoadAddress(rbx, ref);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000399
ager@chromium.orga1645e22009-09-09 19:27:10 +0000400 CEntryStub stub(1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000401 __ CallStub(&stub);
402}
403
404
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000405// Number of pointers to be reserved on stack for fast API call.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000406static const int kFastApiCallArguments = 4;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000407
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000408
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000409// Reserves space for the extra arguments to API function in the
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000410// caller's frame.
411//
412// These arguments are set by CheckPrototypes and GenerateFastApiCall.
413static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
414 // ----------- S t a t e -------------
415 // -- rsp[0] : return address
416 // -- rsp[8] : last argument in the internal frame of the caller
417 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +0000418 __ movq(scratch, Operand(rsp, 0));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000419 __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
ager@chromium.orgac091b72010-05-05 07:34:42 +0000420 __ movq(Operand(rsp, 0), scratch);
421 __ Move(scratch, Smi::FromInt(0));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000422 for (int i = 1; i <= kFastApiCallArguments; i++) {
423 __ movq(Operand(rsp, i * kPointerSize), scratch);
424 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000425}
426
427
428// Undoes the effects of ReserveSpaceForFastApiCall.
429static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
430 // ----------- S t a t e -------------
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000431 // -- rsp[0] : return address.
432 // -- rsp[8] : last fast api call extra argument.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000433 // -- ...
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000434 // -- rsp[kFastApiCallArguments * 8] : first fast api call extra argument.
435 // -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal
436 // frame.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000437 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +0000438 __ movq(scratch, Operand(rsp, 0));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000439 __ movq(Operand(rsp, kFastApiCallArguments * kPointerSize), scratch);
440 __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000441}
442
443
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000444// Generates call to API function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000445static void GenerateFastApiCall(MacroAssembler* masm,
446 const CallOptimization& optimization,
447 int argc) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000448 // ----------- S t a t e -------------
449 // -- rsp[0] : return address
450 // -- rsp[8] : object passing the type check
451 // (last fast api call extra argument,
452 // set by CheckPrototypes)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000453 // -- rsp[16] : api function
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000454 // (first fast api call extra argument)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000455 // -- rsp[24] : api call data
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000456 // -- rsp[32] : isolate
457 // -- rsp[40] : last argument
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000458 // -- ...
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000459 // -- rsp[(argc + 4) * 8] : first argument
460 // -- rsp[(argc + 5) * 8] : receiver
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000461 // -----------------------------------
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000462 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000463 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000464 __ LoadHeapObject(rdi, function);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000465 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
466
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000467 // Pass the additional arguments.
468 __ movq(Operand(rsp, 2 * kPointerSize), rdi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000469 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
470 Handle<Object> call_data(api_call_info->data());
471 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
472 __ Move(rcx, api_call_info);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000473 __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000474 __ movq(Operand(rsp, 3 * kPointerSize), rbx);
475 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000476 __ Move(Operand(rsp, 3 * kPointerSize), call_data);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000477 }
jkummerow@chromium.org3ee08a62012-04-13 13:01:33 +0000478 __ movq(kScratchRegister, ExternalReference::isolate_address());
479 __ movq(Operand(rsp, 4 * kPointerSize), kScratchRegister);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000480
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000481 // Prepare arguments.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000482 __ lea(rbx, Operand(rsp, 4 * kPointerSize));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000483
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000484#if defined(__MINGW64__)
485 Register arguments_arg = rcx;
486#elif defined(_WIN64)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000487 // Win64 uses first register--rcx--for returned value.
488 Register arguments_arg = rdx;
489#else
490 Register arguments_arg = rdi;
491#endif
492
493 // Allocate the v8::Arguments structure in the arguments' space since
494 // it's not controlled by GC.
495 const int kApiStackSpace = 4;
496
497 __ PrepareCallApiFunction(kApiStackSpace);
498
499 __ movq(StackSpaceOperand(0), rbx); // v8::Arguments::implicit_args_.
500 __ addq(rbx, Immediate(argc * kPointerSize));
501 __ movq(StackSpaceOperand(1), rbx); // v8::Arguments::values_.
502 __ Set(StackSpaceOperand(2), argc); // v8::Arguments::length_.
503 // v8::Arguments::is_construct_call_.
504 __ Set(StackSpaceOperand(3), 0);
505
506 // v8::InvocationCallback's argument.
507 __ lea(arguments_arg, StackSpaceOperand(0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000508
509 // Function address is a foreign pointer outside V8's heap.
510 Address function_address = v8::ToCData<Address>(api_call_info->callback());
511 __ CallApiFunctionAndReturn(function_address,
512 argc + kFastApiCallArguments + 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000513}
514
515
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000516class CallInterceptorCompiler BASE_EMBEDDED {
517 public:
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000518 CallInterceptorCompiler(StubCompiler* stub_compiler,
519 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000520 Register name,
521 Code::ExtraICState extra_ic_state)
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000522 : stub_compiler_(stub_compiler),
523 arguments_(arguments),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000524 name_(name),
525 extra_ic_state_(extra_ic_state) {}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000526
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000527 void Compile(MacroAssembler* masm,
528 Handle<JSObject> object,
529 Handle<JSObject> holder,
530 Handle<String> name,
531 LookupResult* lookup,
532 Register receiver,
533 Register scratch1,
534 Register scratch2,
535 Register scratch3,
536 Label* miss) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000537 ASSERT(holder->HasNamedInterceptor());
538 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
539
540 // Check that the receiver isn't a smi.
541 __ JumpIfSmi(receiver, miss);
542
543 CallOptimization optimization(lookup);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000544 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000545 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
546 holder, lookup, name, optimization, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000547 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000548 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
549 name, holder, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000550 }
551 }
552
553 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000554 void CompileCacheable(MacroAssembler* masm,
555 Handle<JSObject> object,
556 Register receiver,
557 Register scratch1,
558 Register scratch2,
559 Register scratch3,
560 Handle<JSObject> interceptor_holder,
561 LookupResult* lookup,
562 Handle<String> name,
563 const CallOptimization& optimization,
564 Label* miss_label) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000565 ASSERT(optimization.is_constant_call());
ager@chromium.org5c838252010-02-19 08:53:10 +0000566 ASSERT(!lookup->holder()->IsGlobalObject());
567
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000568 int depth1 = kInvalidProtoDepth;
569 int depth2 = kInvalidProtoDepth;
570 bool can_do_fast_api_call = false;
571 if (optimization.is_simple_api_call() &&
572 !lookup->holder()->IsGlobalObject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000573 depth1 = optimization.GetPrototypeDepthOfExpectedType(
574 object, interceptor_holder);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000575 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000576 depth2 = optimization.GetPrototypeDepthOfExpectedType(
577 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000578 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000579 can_do_fast_api_call =
580 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000581 }
582
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000583 Counters* counters = masm->isolate()->counters();
584 __ IncrementCounter(counters->call_const_interceptor(), 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000585
586 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000587 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000588 ReserveSpaceForFastApiCall(masm, scratch1);
589 }
590
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000591 // Check that the maps from receiver to interceptor's holder
592 // haven't changed and thus we can invoke interceptor.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000593 Label miss_cleanup;
594 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
595 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000596 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
597 scratch1, scratch2, scratch3,
598 name, depth1, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000599
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000600 // Invoke an interceptor and if it provides a value,
601 // branch to |regular_invoke|.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000602 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000603 LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
604 &regular_invoke);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000605
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000606 // Interceptor returned nothing for this property. Try to use cached
607 // constant function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000608
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000609 // Check that the maps from interceptor's holder to constant function's
610 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000611 if (*interceptor_holder != lookup->holder()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000612 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000613 Handle<JSObject>(lookup->holder()),
614 scratch1, scratch2, scratch3,
615 name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000616 } else {
617 // CheckPrototypes has a side effect of fetching a 'holder'
618 // for API (object which is instanceof for the signature). It's
619 // safe to omit it here, as if present, it should be fetched
620 // by the previous CheckPrototypes.
621 ASSERT(depth2 == kInvalidProtoDepth);
622 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000623
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000624 // Invoke function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000625 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000626 GenerateFastApiCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000627 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000628 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
629 ? CALL_AS_FUNCTION
630 : CALL_AS_METHOD;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000631 __ InvokeFunction(optimization.constant_function(), arguments_,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000632 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000633 }
634
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000635 // Deferred code for fast API call case---clean preallocated space.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000636 if (can_do_fast_api_call) {
637 __ bind(&miss_cleanup);
638 FreeSpaceForFastApiCall(masm, scratch1);
639 __ jmp(miss_label);
640 }
641
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000642 // Invoke a regular function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000643 __ bind(&regular_invoke);
644 if (can_do_fast_api_call) {
645 FreeSpaceForFastApiCall(masm, scratch1);
646 }
647 }
648
649 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000650 Handle<JSObject> object,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000651 Register receiver,
652 Register scratch1,
653 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000654 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000655 Handle<String> name,
656 Handle<JSObject> interceptor_holder,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000657 Label* miss_label) {
658 Register holder =
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000659 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000660 scratch1, scratch2, scratch3,
661 name, miss_label);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000662
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000663 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000664 // Save the name_ register across the call.
665 __ push(name_);
666
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000667 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000668
669 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000670 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
671 masm->isolate()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000672 6);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000673
674 // Restore the name_ register.
675 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000676
677 // Leave the internal frame.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000678 }
679
680 void LoadWithInterceptor(MacroAssembler* masm,
681 Register receiver,
682 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000683 Handle<JSObject> holder_obj,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000684 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000685 {
686 FrameScope scope(masm, StackFrame::INTERNAL);
687 __ push(holder); // Save the holder.
688 __ push(name_); // Save the name.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000689
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000690 CompileCallLoadPropertyWithInterceptor(masm,
691 receiver,
692 holder,
693 name_,
694 holder_obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000695
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000696 __ pop(name_); // Restore the name.
697 __ pop(receiver); // Restore the holder.
698 // Leave the internal frame.
699 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000700
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000701 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000702 __ j(not_equal, interceptor_succeeded);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000703 }
704
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000705 StubCompiler* stub_compiler_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000706 const ParameterCount& arguments_;
ager@chromium.org5c838252010-02-19 08:53:10 +0000707 Register name_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000708 Code::ExtraICState extra_ic_state_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000709};
710
711
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000712void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
713 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000714 Handle<Code> code = (kind == Code::LOAD_IC)
715 ? masm->isolate()->builtins()->LoadIC_Miss()
716 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
717 __ Jump(code, RelocInfo::CODE_TARGET);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000718}
719
720
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000721void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000722 Handle<Code> code =
723 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
724 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000725}
726
727
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000728// Both name_reg and receiver_reg are preserved on jumps to miss_label,
729// but may be destroyed if store is successful.
730void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000731 Handle<JSObject> object,
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000732 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000733 Handle<Map> transition,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000734 Handle<String> name,
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000735 Register receiver_reg,
736 Register name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000737 Register scratch1,
738 Register scratch2,
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000739 Label* miss_label) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000740 LookupResult lookup(masm->isolate());
741 object->Lookup(*name, &lookup);
742 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
743 // In sloppy mode, we could just return the value and be done. However, we
744 // might be in strict mode, where we have to throw. Since we cannot tell,
745 // go into slow case unconditionally.
746 __ jmp(miss_label);
747 return;
748 }
749
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000750 // Check that the map of the object hasn't changed.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000751 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
752 : REQUIRE_EXACT_MAP;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000753 __ CheckMap(receiver_reg, Handle<Map>(object->map()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000754 miss_label, DO_SMI_CHECK, mode);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000755
756 // Perform global security token check if needed.
757 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000758 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
759 }
760
761 // Check that we are allowed to write this.
762 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
763 JSObject* holder;
764 if (lookup.IsFound()) {
765 holder = lookup.holder();
766 } else {
767 // Find the top object.
768 holder = *object;
769 do {
770 holder = JSObject::cast(holder->GetPrototype());
771 } while (holder->GetPrototype()->IsJSObject());
772 }
773 // We need an extra register, push
774 __ push(name_reg);
775 Label miss_pop, done_check;
776 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
777 scratch1, scratch2, name, &miss_pop);
778 __ jmp(&done_check);
779 __ bind(&miss_pop);
780 __ pop(name_reg);
781 __ jmp(miss_label);
782 __ bind(&done_check);
783 __ pop(name_reg);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000784 }
785
786 // Stub never generated for non-global objects that require access
787 // checks.
788 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
789
790 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000791 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000792 // The properties must be extended before we can store the value.
793 // We jump to a runtime call that extends the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000794 __ pop(scratch1); // Return address.
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000795 __ push(receiver_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000796 __ Push(transition);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000797 __ push(rax);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000798 __ push(scratch1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000799 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000800 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
801 masm->isolate()),
802 3,
803 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000804 return;
805 }
806
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000807 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +0000808 // Update the map of the object.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000809 __ Move(scratch1, transition);
810 __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000811
812 // Update the write barrier for the map field and pass the now unused
813 // name_reg as scratch register.
814 __ RecordWriteField(receiver_reg,
815 HeapObject::kMapOffset,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000816 scratch1,
verwaest@chromium.org37141392012-05-31 13:27:02 +0000817 name_reg,
818 kDontSaveFPRegs,
819 OMIT_REMEMBERED_SET,
820 OMIT_SMI_CHECK);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000821 }
822
823 // Adjust for the number of properties stored in the object. Even in the
824 // face of a transition we can use the old map here because the size of the
825 // object and the number of in-object properties is not going to change.
826 index -= object->map()->inobject_properties();
827
828 if (index < 0) {
829 // Set the property straight into the object.
830 int offset = object->map()->instance_size() + (index * kPointerSize);
831 __ movq(FieldOperand(receiver_reg, offset), rax);
832
833 // Update the write barrier for the array address.
834 // Pass the value being stored in the now unused name_reg.
835 __ movq(name_reg, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000836 __ RecordWriteField(
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000837 receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000838 } else {
839 // Write to the properties array.
840 int offset = index * kPointerSize + FixedArray::kHeaderSize;
841 // Get the properties array (optimistically).
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000842 __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
843 __ movq(FieldOperand(scratch1, offset), rax);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000844
845 // Update the write barrier for the array address.
846 // Pass the value being stored in the now unused name_reg.
847 __ movq(name_reg, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000848 __ RecordWriteField(
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000849 scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000850 }
851
852 // Return the value (register rax).
853 __ ret(0);
854}
855
856
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000857// Generate code to check that a global property cell is empty. Create
858// the property cell at compilation time if no cell exists for the
859// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000860static void GenerateCheckPropertyCell(MacroAssembler* masm,
861 Handle<GlobalObject> global,
862 Handle<String> name,
863 Register scratch,
864 Label* miss) {
865 Handle<JSGlobalPropertyCell> cell =
866 GlobalObject::EnsurePropertyCell(global, name);
867 ASSERT(cell->value()->IsTheHole());
868 __ Move(scratch, cell);
869 __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
870 masm->isolate()->factory()->the_hole_value());
871 __ j(not_equal, miss);
872}
873
874
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000875// Calls GenerateCheckPropertyCell for each global object in the prototype chain
876// from object to (but not including) holder.
877static void GenerateCheckPropertyCells(MacroAssembler* masm,
878 Handle<JSObject> object,
879 Handle<JSObject> holder,
880 Handle<String> name,
881 Register scratch,
882 Label* miss) {
883 Handle<JSObject> current = object;
884 while (!current.is_identical_to(holder)) {
885 if (current->IsGlobalObject()) {
886 GenerateCheckPropertyCell(masm,
887 Handle<GlobalObject>::cast(current),
888 name,
889 scratch,
890 miss);
891 }
892 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
893 }
894}
895
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000896#undef __
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000897#define __ ACCESS_MASM((masm()))
898
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000899
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000900Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
901 Register object_reg,
902 Handle<JSObject> holder,
903 Register holder_reg,
904 Register scratch1,
905 Register scratch2,
906 Handle<String> name,
907 int save_at_depth,
908 Label* miss) {
909 // Make sure there's no overlap between holder and object registers.
910 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
911 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
912 && !scratch2.is(scratch1));
913
914 // Keep track of the current object in register reg. On the first
915 // iteration, reg is an alias for object_reg, on later iterations,
916 // it is an alias for holder_reg.
917 Register reg = object_reg;
918 int depth = 0;
919
920 if (save_at_depth == depth) {
921 __ movq(Operand(rsp, kPointerSize), object_reg);
922 }
923
924 // Check the maps in the prototype chain.
925 // Traverse the prototype chain from the object and do map checks.
926 Handle<JSObject> current = object;
927 while (!current.is_identical_to(holder)) {
928 ++depth;
929
930 // Only global objects and objects that do not require access
931 // checks are allowed in stubs.
932 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
933
934 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
935 if (!current->HasFastProperties() &&
936 !current->IsJSGlobalObject() &&
937 !current->IsJSGlobalProxy()) {
938 if (!name->IsSymbol()) {
939 name = factory()->LookupSymbol(name);
940 }
941 ASSERT(current->property_dictionary()->FindEntry(*name) ==
942 StringDictionary::kNotFound);
943
944 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
945 scratch1, scratch2);
946
947 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
948 reg = holder_reg; // From now on the object will be in holder_reg.
949 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
950 } else {
951 bool in_new_space = heap()->InNewSpace(*prototype);
952 Handle<Map> current_map(current->map());
953 if (in_new_space) {
954 // Save the map in scratch1 for later.
955 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000956 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000957 __ CheckMap(reg, Handle<Map>(current_map),
958 miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
959
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000960 // Check access rights to the global object. This has to happen after
961 // the map check so that we know that the object is actually a global
962 // object.
963 if (current->IsJSGlobalProxy()) {
964 __ CheckAccessGlobalProxy(reg, scratch2, miss);
965 }
966 reg = holder_reg; // From now on the object will be in holder_reg.
967
968 if (in_new_space) {
969 // The prototype is in new space; we cannot store a reference to it
970 // in the code. Load it from the map.
971 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
972 } else {
973 // The prototype is in old space; load it directly.
974 __ Move(reg, prototype);
975 }
976 }
977
978 if (save_at_depth == depth) {
979 __ movq(Operand(rsp, kPointerSize), reg);
980 }
981
982 // Go to the next object in the prototype chain.
983 current = prototype;
984 }
985 ASSERT(current.is_identical_to(holder));
986
987 // Log the check depth.
988 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
989
990 // Check the holder map.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000991 __ CheckMap(reg, Handle<Map>(holder->map()),
992 miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000993
994 // Perform security check for access to the global object.
995 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
996 if (current->IsJSGlobalProxy()) {
997 __ CheckAccessGlobalProxy(reg, scratch1, miss);
998 }
999
1000 // If we've skipped any global objects, it's not enough to verify that
1001 // their maps haven't changed. We also need to check that the property
1002 // cell for the property is still empty.
1003 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1004
1005 // Return the register containing the holder.
1006 return reg;
1007}
1008
1009
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001010void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1011 Handle<JSObject> holder,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001012 Register receiver,
1013 Register scratch1,
1014 Register scratch2,
1015 Register scratch3,
1016 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001017 Handle<String> name,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001018 Label* miss) {
1019 // Check that the receiver isn't a smi.
1020 __ JumpIfSmi(receiver, miss);
1021
1022 // Check the prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001023 Register reg = CheckPrototypes(
1024 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001025
1026 // Get the value from the properties.
1027 GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
1028 __ ret(0);
1029}
1030
1031
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001032void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1033 Handle<JSObject> holder,
1034 Register receiver,
1035 Register name_reg,
1036 Register scratch1,
1037 Register scratch2,
1038 Register scratch3,
1039 Handle<AccessorInfo> callback,
1040 Handle<String> name,
1041 Label* miss) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001042 // Check that the receiver isn't a smi.
1043 __ JumpIfSmi(receiver, miss);
1044
1045 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001046 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1047 scratch2, scratch3, name, miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001048
1049 // Insert additional parameters into the stack frame above return address.
1050 ASSERT(!scratch2.is(reg));
1051 __ pop(scratch2); // Get return address to place it below.
1052
1053 __ push(receiver); // receiver
1054 __ push(reg); // holder
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001055 if (heap()->InNewSpace(callback->data())) {
1056 __ Move(scratch1, callback);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001057 __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); // data
1058 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001059 __ Push(Handle<Object>(callback->data()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001060 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001061 __ PushAddress(ExternalReference::isolate_address()); // isolate
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001062 __ push(name_reg); // name
1063 // Save a pointer to where we pushed the arguments pointer.
1064 // This will be passed as the const AccessorInfo& to the C++ callback.
1065
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001066#if defined(__MINGW64__)
1067 Register accessor_info_arg = rdx;
1068 Register name_arg = rcx;
1069#elif defined(_WIN64)
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001070 // Win64 uses first register--rcx--for returned value.
1071 Register accessor_info_arg = r8;
1072 Register name_arg = rdx;
1073#else
1074 Register accessor_info_arg = rsi;
1075 Register name_arg = rdi;
1076#endif
1077
1078 ASSERT(!name_arg.is(scratch2));
1079 __ movq(name_arg, rsp);
1080 __ push(scratch2); // Restore return address.
1081
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001082 // 4 elements array for v8::Arguments::values_ and handler for name.
1083 const int kStackSpace = 5;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001084
1085 // Allocate v8::AccessorInfo in non-GCed stack space.
1086 const int kArgStackSpace = 1;
1087
1088 __ PrepareCallApiFunction(kArgStackSpace);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001089 __ lea(rax, Operand(name_arg, 4 * kPointerSize));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001090
1091 // v8::AccessorInfo::args_.
1092 __ movq(StackSpaceOperand(0), rax);
1093
1094 // The context register (rsi) has been saved in PrepareCallApiFunction and
1095 // could be used to pass arguments.
1096 __ lea(accessor_info_arg, StackSpaceOperand(0));
1097
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001098 Address getter_address = v8::ToCData<Address>(callback->getter());
1099 __ CallApiFunctionAndReturn(getter_address, kStackSpace);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001100}
1101
1102
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001103void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1104 Handle<JSObject> holder,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001105 Register receiver,
1106 Register scratch1,
1107 Register scratch2,
1108 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001109 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001110 Handle<String> name,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001111 Label* miss) {
1112 // Check that the receiver isn't a smi.
1113 __ JumpIfSmi(receiver, miss);
1114
1115 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001116 CheckPrototypes(
1117 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001118
1119 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001120 __ LoadHeapObject(rax, value);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001121 __ ret(0);
1122}
1123
1124
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001125void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1126 Handle<JSObject> interceptor_holder,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001127 LookupResult* lookup,
1128 Register receiver,
1129 Register name_reg,
1130 Register scratch1,
1131 Register scratch2,
1132 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001133 Handle<String> name,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001134 Label* miss) {
1135 ASSERT(interceptor_holder->HasNamedInterceptor());
1136 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1137
1138 // Check that the receiver isn't a smi.
1139 __ JumpIfSmi(receiver, miss);
1140
1141 // So far the most popular follow ups for interceptor loads are FIELD
1142 // and CALLBACKS, so inline only them, other cases may be added
1143 // later.
1144 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001145 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001146 if (lookup->IsField()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001147 compile_followup_inline = true;
1148 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001149 lookup->GetCallbackObject()->IsAccessorInfo()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001150 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1151 compile_followup_inline = callback->getter() != NULL &&
1152 callback->IsCompatibleReceiver(*object);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001153 }
1154 }
1155
1156 if (compile_followup_inline) {
1157 // Compile the interceptor call, followed by inline code to load the
1158 // property from further up the prototype chain if the call fails.
1159 // Check that the maps haven't changed.
1160 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1161 scratch1, scratch2, scratch3,
1162 name, miss);
1163 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1164
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001165 // Preserve the receiver register explicitly whenever it is different from
1166 // the holder and it is needed should the interceptor return without any
1167 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1168 // the FIELD case might cause a miss during the prototype check.
1169 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1170 bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1171 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1172
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001173 // Save necessary data before invoking an interceptor.
1174 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001175 {
1176 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001177
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001178 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001179 __ push(receiver);
1180 }
1181 __ push(holder_reg);
1182 __ push(name_reg);
1183
1184 // Invoke an interceptor. Note: map checks from receiver to
1185 // interceptor's holder has been compiled before (see a caller
1186 // of this method.)
1187 CompileCallLoadPropertyWithInterceptor(masm(),
1188 receiver,
1189 holder_reg,
1190 name_reg,
1191 interceptor_holder);
1192
1193 // Check if interceptor provided a value for property. If it's
1194 // the case, return immediately.
1195 Label interceptor_failed;
1196 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
1197 __ j(equal, &interceptor_failed);
1198 frame_scope.GenerateLeaveFrame();
1199 __ ret(0);
1200
1201 __ bind(&interceptor_failed);
1202 __ pop(name_reg);
1203 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001204 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001205 __ pop(receiver);
1206 }
1207
1208 // Leave the internal frame.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001209 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001210
1211 // Check that the maps from interceptor's holder to lookup's holder
1212 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001213 if (must_perfrom_prototype_check) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001214 holder_reg = CheckPrototypes(interceptor_holder,
1215 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001216 Handle<JSObject>(lookup->holder()),
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001217 scratch1,
1218 scratch2,
1219 scratch3,
1220 name,
1221 miss);
1222 }
1223
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001224 if (lookup->IsField()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001225 // We found FIELD property in prototype chain of interceptor's holder.
1226 // Retrieve a field from field's holder.
1227 GenerateFastPropertyLoad(masm(), rax, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001228 Handle<JSObject>(lookup->holder()),
1229 lookup->GetFieldIndex());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001230 __ ret(0);
1231 } else {
1232 // We found CALLBACKS property in prototype chain of interceptor's
1233 // holder.
1234 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001235 Handle<AccessorInfo> callback(
1236 AccessorInfo::cast(lookup->GetCallbackObject()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001237 ASSERT(callback->getter() != NULL);
1238
1239 // Tail call to runtime.
1240 // Important invariant in CALLBACKS case: the code above must be
1241 // structured to never clobber |receiver| register.
1242 __ pop(scratch2); // return address
1243 __ push(receiver);
1244 __ push(holder_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001245 __ Move(holder_reg, callback);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001246 __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001247 __ PushAddress(ExternalReference::isolate_address());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001248 __ push(holder_reg);
1249 __ push(name_reg);
1250 __ push(scratch2); // restore return address
1251
1252 ExternalReference ref =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001253 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001254 isolate());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001255 __ TailCallExternalReference(ref, 6, 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001256 }
1257 } else { // !compile_followup_inline
1258 // Call the runtime system to load the interceptor.
1259 // Check that the maps haven't changed.
1260 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1261 scratch1, scratch2, scratch3,
1262 name, miss);
1263 __ pop(scratch2); // save old return address
1264 PushInterceptorArguments(masm(), receiver, holder_reg,
1265 name_reg, interceptor_holder);
1266 __ push(scratch2); // restore old return address
1267
1268 ExternalReference ref = ExternalReference(
lrn@chromium.org7516f052011-03-30 08:52:27 +00001269 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001270 __ TailCallExternalReference(ref, 6, 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001271 }
1272}
1273
1274
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001275void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001276 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001277 __ Cmp(rcx, name);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001278 __ j(not_equal, miss);
1279 }
1280}
1281
1282
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001283void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1284 Handle<JSObject> holder,
1285 Handle<String> name,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001286 Label* miss) {
1287 ASSERT(holder->IsGlobalObject());
1288
1289 // Get the number of arguments.
1290 const int argc = arguments().immediate();
1291
1292 // Get the receiver from the stack.
1293 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1294
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001295
1296 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001297 __ JumpIfSmi(rdx, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001298 CheckPrototypes(object, rdx, holder, rbx, rax, rdi, name, miss);
1299}
1300
1301
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001302void CallStubCompiler::GenerateLoadFunctionFromCell(
1303 Handle<JSGlobalPropertyCell> cell,
1304 Handle<JSFunction> function,
1305 Label* miss) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001306 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001307 __ Move(rdi, cell);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001308 __ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset));
1309
1310 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001311 if (heap()->InNewSpace(*function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001312 // We can't embed a pointer to a function in new space so we have
1313 // to verify that the shared function info is unchanged. This has
1314 // the nice side effect that multiple closures based on the same
1315 // function can all use this call IC. Before we load through the
1316 // function, we have to verify that it still is a function.
1317 __ JumpIfSmi(rdi, miss);
1318 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax);
1319 __ j(not_equal, miss);
1320
1321 // Check the shared function info. Make sure it hasn't changed.
1322 __ Move(rax, Handle<SharedFunctionInfo>(function->shared()));
1323 __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001324 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001325 __ Cmp(rdi, function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001326 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001327 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001328}
1329
1330
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001331void CallStubCompiler::GenerateMissBranch() {
1332 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001333 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1334 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001335 extra_state_);
1336 __ Jump(code, RelocInfo::CODE_TARGET);
1337}
1338
1339
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001340Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1341 Handle<JSObject> holder,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001342 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001343 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001344 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001345 // rcx : function name
1346 // rsp[0] : return address
1347 // rsp[8] : argument argc
1348 // rsp[16] : argument argc - 1
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001349 // ...
ager@chromium.org5c838252010-02-19 08:53:10 +00001350 // rsp[argc * 8] : argument 1
1351 // rsp[(argc + 1) * 8] : argument 0 = receiver
1352 // -----------------------------------
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001353 Label miss;
1354
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001355 GenerateNameCheck(name, &miss);
1356
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001357 // Get the receiver from the stack.
1358 const int argc = arguments().immediate();
1359 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1360
1361 // Check that the receiver isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001362 __ JumpIfSmi(rdx, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001363
1364 // Do the right check and compute the holder register.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001365 Register reg = CheckPrototypes(object, rdx, holder, rbx, rax, rdi,
1366 name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001367
1368 GenerateFastPropertyLoad(masm(), rdi, reg, holder, index);
1369
1370 // Check that the function really is a function.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001371 __ JumpIfSmi(rdi, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001372 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rbx);
1373 __ j(not_equal, &miss);
1374
1375 // Patch the receiver on the stack with the global proxy if
1376 // necessary.
1377 if (object->IsGlobalObject()) {
1378 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
1379 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
1380 }
1381
1382 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001383 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001384 ? CALL_AS_FUNCTION
1385 : CALL_AS_METHOD;
1386 __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
1387 NullCallWrapper(), call_kind);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001388
1389 // Handle call cache miss.
1390 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001391 GenerateMissBranch();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001392
1393 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001394 return GetCode(Code::FIELD, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001395}
1396
1397
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001398Handle<Code> CallStubCompiler::CompileArrayPushCall(
1399 Handle<Object> object,
1400 Handle<JSObject> holder,
1401 Handle<JSGlobalPropertyCell> cell,
1402 Handle<JSFunction> function,
1403 Handle<String> name) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001404 // ----------- S t a t e -------------
1405 // -- rcx : name
1406 // -- rsp[0] : return address
1407 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1408 // -- ...
1409 // -- rsp[(argc + 1) * 8] : receiver
1410 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +00001411
1412 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001413 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001414
1415 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001416 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001417
ager@chromium.orgac091b72010-05-05 07:34:42 +00001418 // Get the receiver from the stack.
1419 const int argc = arguments().immediate();
1420 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1421
1422 // Check that the receiver isn't a smi.
1423 __ JumpIfSmi(rdx, &miss);
1424
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001425 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
1426 name, &miss);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001427
1428 if (argc == 0) {
1429 // Noop, return the length.
1430 __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset));
1431 __ ret((argc + 1) * kPointerSize);
1432 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001433 Label call_builtin;
1434
ager@chromium.orgac091b72010-05-05 07:34:42 +00001435 if (argc == 1) { // Otherwise fall through to call builtin.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001436 Label attempt_to_grow_elements, with_write_barrier;
ager@chromium.orgac091b72010-05-05 07:34:42 +00001437
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001438 // Get the elements array of the object.
1439 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
1440
1441 // Check that the elements are in fast mode and writable.
1442 __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
1443 factory()->fixed_array_map());
1444 __ j(not_equal, &call_builtin);
1445
ager@chromium.orgac091b72010-05-05 07:34:42 +00001446 // Get the array's length into rax and calculate new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001447 __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001448 STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001449 __ addl(rax, Immediate(argc));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001450
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001451 // Get the elements' length into rcx.
1452 __ SmiToInteger32(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001453
1454 // Check if we could survive without allocation.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001455 __ cmpl(rax, rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001456 __ j(greater, &attempt_to_grow_elements);
1457
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001458 // Check if value is a smi.
1459 __ movq(rcx, Operand(rsp, argc * kPointerSize));
1460 __ JumpIfNotSmi(rcx, &with_write_barrier);
1461
ager@chromium.orgac091b72010-05-05 07:34:42 +00001462 // Save new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001463 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001464
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001465 // Store the value.
1466 __ movq(FieldOperand(rdi,
1467 rax,
1468 times_pointer_size,
1469 FixedArray::kHeaderSize - argc * kPointerSize),
1470 rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001471
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001472 __ Integer32ToSmi(rax, rax); // Return new length as smi.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001473 __ ret((argc + 1) * kPointerSize);
1474
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001475 __ bind(&with_write_barrier);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001476
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001477 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
1478
1479 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1480 Label fast_object, not_fast_object;
1481 __ CheckFastObjectElements(rbx, &not_fast_object, Label::kNear);
1482 __ jmp(&fast_object);
1483 // In case of fast smi-only, convert to fast object, otherwise bail out.
1484 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001485 __ CheckFastSmiElements(rbx, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001486 // rdx: receiver
1487 // rbx: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001488
1489 Label try_holey_map;
1490 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001491 FAST_ELEMENTS,
1492 rbx,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001493 rdi,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001494 &try_holey_map);
1495
1496 ElementsTransitionGenerator::
1497 GenerateMapChangeElementsTransition(masm());
1498 // Restore edi.
1499 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
1500 __ jmp(&fast_object);
1501
1502 __ bind(&try_holey_map);
1503 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1504 FAST_HOLEY_ELEMENTS,
1505 rbx,
1506 rdi,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001507 &call_builtin);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001508 ElementsTransitionGenerator::
1509 GenerateMapChangeElementsTransition(masm());
1510 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001511 __ bind(&fast_object);
1512 } else {
1513 __ CheckFastObjectElements(rbx, &call_builtin);
1514 }
1515
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001516 // Save new length.
1517 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001518
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001519 // Store the value.
1520 __ lea(rdx, FieldOperand(rdi,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001521 rax, times_pointer_size,
1522 FixedArray::kHeaderSize - argc * kPointerSize));
1523 __ movq(Operand(rdx, 0), rcx);
1524
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001525 __ RecordWrite(rdi, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001526 OMIT_SMI_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001527
1528 __ Integer32ToSmi(rax, rax); // Return new length as smi.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001529 __ ret((argc + 1) * kPointerSize);
1530
1531 __ bind(&attempt_to_grow_elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001532 if (!FLAG_inline_new) {
1533 __ jmp(&call_builtin);
1534 }
1535
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001536 __ movq(rbx, Operand(rsp, argc * kPointerSize));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001537 // Growing elements that are SMI-only requires special handling in case
1538 // the new element is non-Smi. For now, delegate to the builtin.
1539 Label no_fast_elements_check;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001540 __ JumpIfSmi(rbx, &no_fast_elements_check);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001541 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
1542 __ CheckFastObjectElements(rcx, &call_builtin, Label::kFar);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001543 __ bind(&no_fast_elements_check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001544
ager@chromium.orgac091b72010-05-05 07:34:42 +00001545 ExternalReference new_space_allocation_top =
lrn@chromium.org7516f052011-03-30 08:52:27 +00001546 ExternalReference::new_space_allocation_top_address(isolate());
ager@chromium.orgac091b72010-05-05 07:34:42 +00001547 ExternalReference new_space_allocation_limit =
lrn@chromium.org7516f052011-03-30 08:52:27 +00001548 ExternalReference::new_space_allocation_limit_address(isolate());
ager@chromium.orgac091b72010-05-05 07:34:42 +00001549
1550 const int kAllocationDelta = 4;
1551 // Load top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001552 __ Load(rcx, new_space_allocation_top);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001553
1554 // Check if it's the end of elements.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001555 __ lea(rdx, FieldOperand(rdi,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001556 rax, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001557 FixedArray::kHeaderSize - argc * kPointerSize));
1558 __ cmpq(rdx, rcx);
1559 __ j(not_equal, &call_builtin);
1560 __ addq(rcx, Immediate(kAllocationDelta * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001561 Operand limit_operand =
1562 masm()->ExternalOperand(new_space_allocation_limit);
1563 __ cmpq(rcx, limit_operand);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001564 __ j(above, &call_builtin);
1565
1566 // We fit and could grow elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001567 __ Store(new_space_allocation_top, rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001568
1569 // Push the argument...
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001570 __ movq(Operand(rdx, 0), rbx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001571 // ... and fill the rest with holes.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001572 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001573 for (int i = 1; i < kAllocationDelta; i++) {
1574 __ movq(Operand(rdx, i * kPointerSize), kScratchRegister);
1575 }
1576
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001577 // We know the elements array is in new space so we don't need the
1578 // remembered set, but we just pushed a value onto it so we may have to
1579 // tell the incremental marker to rescan the object that we just grew. We
1580 // don't need to worry about the holes because they are in old space and
1581 // already marked black.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001582 __ RecordWrite(rdi, rdx, rbx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001583
ager@chromium.orgac091b72010-05-05 07:34:42 +00001584 // Restore receiver to rdx as finish sequence assumes it's here.
1585 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1586
1587 // Increment element's and array's sizes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001588 __ SmiAddConstant(FieldOperand(rdi, FixedArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001589 Smi::FromInt(kAllocationDelta));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001590
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001591 // Make new length a smi before returning it.
1592 __ Integer32ToSmi(rax, rax);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001593 __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001594
ager@chromium.orgac091b72010-05-05 07:34:42 +00001595 __ ret((argc + 1) * kPointerSize);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001596 }
1597
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001598 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001599 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001600 isolate()),
ager@chromium.orgac091b72010-05-05 07:34:42 +00001601 argc + 1,
1602 1);
1603 }
1604
1605 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001606 GenerateMissBranch();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001607
1608 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001609 return GetCode(function);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001610}
1611
1612
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001613Handle<Code> CallStubCompiler::CompileArrayPopCall(
1614 Handle<Object> object,
1615 Handle<JSObject> holder,
1616 Handle<JSGlobalPropertyCell> cell,
1617 Handle<JSFunction> function,
1618 Handle<String> name) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001619 // ----------- S t a t e -------------
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001620 // -- rcx : name
1621 // -- rsp[0] : return address
1622 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
ager@chromium.orgac091b72010-05-05 07:34:42 +00001623 // -- ...
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001624 // -- rsp[(argc + 1) * 8] : receiver
ager@chromium.orgac091b72010-05-05 07:34:42 +00001625 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +00001626
1627 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001628 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001629
1630 Label miss, return_undefined, call_builtin;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001631 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001632
ager@chromium.orgac091b72010-05-05 07:34:42 +00001633 // Get the receiver from the stack.
1634 const int argc = arguments().immediate();
1635 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1636
1637 // Check that the receiver isn't a smi.
1638 __ JumpIfSmi(rdx, &miss);
1639
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001640 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
1641 name, &miss);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001642
1643 // Get the elements array of the object.
1644 __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
1645
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001646 // Check that the elements are in fast mode and writable.
1647 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
1648 Heap::kFixedArrayMapRootIndex);
1649 __ j(not_equal, &call_builtin);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001650
1651 // Get the array's length into rcx and calculate new length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001652 __ SmiToInteger32(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
1653 __ subl(rcx, Immediate(1));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001654 __ j(negative, &return_undefined);
1655
1656 // Get the last element.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001657 __ LoadRoot(r9, Heap::kTheHoleValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001658 __ movq(rax, FieldOperand(rbx,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001659 rcx, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001660 FixedArray::kHeaderSize));
1661 // Check if element is already the hole.
1662 __ cmpq(rax, r9);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001663 // If so, call slow-case to also check prototypes for value.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001664 __ j(equal, &call_builtin);
1665
1666 // Set the array's length.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001667 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001668
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001669 // Fill with the hole and return original value.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001670 __ movq(FieldOperand(rbx,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001671 rcx, times_pointer_size,
ager@chromium.orgac091b72010-05-05 07:34:42 +00001672 FixedArray::kHeaderSize),
1673 r9);
1674 __ ret((argc + 1) * kPointerSize);
1675
1676 __ bind(&return_undefined);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001677 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001678 __ ret((argc + 1) * kPointerSize);
1679
1680 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 __ TailCallExternalReference(
lrn@chromium.org7516f052011-03-30 08:52:27 +00001682 ExternalReference(Builtins::c_ArrayPop, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001683 argc + 1,
1684 1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001685
ager@chromium.orgac091b72010-05-05 07:34:42 +00001686 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001687 GenerateMissBranch();
ager@chromium.orgac091b72010-05-05 07:34:42 +00001688
1689 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001690 return GetCode(function);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001691}
1692
1693
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001694Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1695 Handle<Object> object,
1696 Handle<JSObject> holder,
1697 Handle<JSGlobalPropertyCell> cell,
1698 Handle<JSFunction> function,
1699 Handle<String> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001700 // ----------- S t a t e -------------
1701 // -- rcx : function name
1702 // -- rsp[0] : return address
1703 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1704 // -- ...
1705 // -- rsp[(argc + 1) * 8] : receiver
1706 // -----------------------------------
1707
1708 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001709 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001710
1711 const int argc = arguments().immediate();
1712
1713 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001714 Label name_miss;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001715 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001716 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001717 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001718 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001719 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001720 index_out_of_range_label = &miss;
1721 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001722 GenerateNameCheck(name, &name_miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001723
1724 // Check that the maps starting from the prototype haven't changed.
1725 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1726 Context::STRING_FUNCTION_INDEX,
1727 rax,
1728 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001729 ASSERT(!object.is_identical_to(holder));
1730 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1731 rax, holder, rbx, rdx, rdi, name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001732
1733 Register receiver = rbx;
1734 Register index = rdi;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001735 Register result = rax;
1736 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
1737 if (argc > 0) {
1738 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
1739 } else {
1740 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1741 }
1742
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001743 StringCharCodeAtGenerator generator(receiver,
1744 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001745 result,
1746 &miss, // When not a string.
1747 &miss, // When not a number.
1748 index_out_of_range_label,
1749 STRING_INDEX_IS_NUMBER);
1750 generator.GenerateFast(masm());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001751 __ ret((argc + 1) * kPointerSize);
1752
1753 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001754 generator.GenerateSlow(masm(), call_helper);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001755
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001756 if (index_out_of_range.is_linked()) {
1757 __ bind(&index_out_of_range);
1758 __ LoadRoot(rax, Heap::kNanValueRootIndex);
1759 __ ret((argc + 1) * kPointerSize);
1760 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001761
1762 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001763 // Restore function name in rcx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001764 __ Move(rcx, name);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001765 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001766 GenerateMissBranch();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001767
1768 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001769 return GetCode(function);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001770}
1771
1772
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001773Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1774 Handle<Object> object,
1775 Handle<JSObject> holder,
1776 Handle<JSGlobalPropertyCell> cell,
1777 Handle<JSFunction> function,
1778 Handle<String> name) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001779 // ----------- S t a t e -------------
1780 // -- rcx : function name
1781 // -- rsp[0] : return address
1782 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1783 // -- ...
1784 // -- rsp[(argc + 1) * 8] : receiver
1785 // -----------------------------------
1786
1787 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001788 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001789
1790 const int argc = arguments().immediate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001791 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001792 Label name_miss;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001793 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001794 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001795 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001796 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001797 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001798 index_out_of_range_label = &miss;
1799 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001800 GenerateNameCheck(name, &name_miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001801
1802 // Check that the maps starting from the prototype haven't changed.
1803 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1804 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001805 rax,
1806 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001807 ASSERT(!object.is_identical_to(holder));
1808 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1809 rax, holder, rbx, rdx, rdi, name, &miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001810
1811 Register receiver = rax;
1812 Register index = rdi;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001813 Register scratch = rdx;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001814 Register result = rax;
1815 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
1816 if (argc > 0) {
1817 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
1818 } else {
1819 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1820 }
1821
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001822 StringCharAtGenerator generator(receiver,
1823 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001824 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001825 result,
1826 &miss, // When not a string.
1827 &miss, // When not a number.
1828 index_out_of_range_label,
1829 STRING_INDEX_IS_NUMBER);
1830 generator.GenerateFast(masm());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001831 __ ret((argc + 1) * kPointerSize);
1832
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001833 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001834 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001835
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001836 if (index_out_of_range.is_linked()) {
1837 __ bind(&index_out_of_range);
1838 __ LoadRoot(rax, Heap::kEmptyStringRootIndex);
1839 __ ret((argc + 1) * kPointerSize);
1840 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001841 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001842 // Restore function name in rcx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001843 __ Move(rcx, name);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001844 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001845 GenerateMissBranch();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001846
1847 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001848 return GetCode(function);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001849}
1850
1851
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001852Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1853 Handle<Object> object,
1854 Handle<JSObject> holder,
1855 Handle<JSGlobalPropertyCell> cell,
1856 Handle<JSFunction> function,
1857 Handle<String> name) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001858 // ----------- S t a t e -------------
1859 // -- rcx : function name
1860 // -- rsp[0] : return address
1861 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1862 // -- ...
1863 // -- rsp[(argc + 1) * 8] : receiver
1864 // -----------------------------------
1865
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001866 // If the object is not a JSObject or we got an unexpected number of
1867 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001868 const int argc = arguments().immediate();
1869 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001870
1871 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001872 GenerateNameCheck(name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001873
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001874 if (cell.is_null()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001875 __ movq(rdx, Operand(rsp, 2 * kPointerSize));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001876 __ JumpIfSmi(rdx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001877 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
1878 name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001879 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001880 ASSERT(cell->value() == *function);
1881 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1882 &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001883 GenerateLoadFunctionFromCell(cell, function, &miss);
1884 }
1885
1886 // Load the char code argument.
1887 Register code = rbx;
1888 __ movq(code, Operand(rsp, 1 * kPointerSize));
1889
1890 // Check the code is a smi.
1891 Label slow;
1892 __ JumpIfNotSmi(code, &slow);
1893
1894 // Convert the smi code to uint16.
1895 __ SmiAndConstant(code, code, Smi::FromInt(0xffff));
1896
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001897 StringCharFromCodeGenerator generator(code, rax);
1898 generator.GenerateFast(masm());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001899 __ ret(2 * kPointerSize);
1900
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001901 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001902 generator.GenerateSlow(masm(), call_helper);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001903
1904 // Tail call the full function. We do not have to patch the receiver
1905 // because the function makes no use of it.
1906 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001907 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001908 ? CALL_AS_FUNCTION
1909 : CALL_AS_METHOD;
1910 __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
1911 NullCallWrapper(), call_kind);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001912
1913 __ bind(&miss);
1914 // rcx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001915 GenerateMissBranch();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001916
1917 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001918 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001919}
1920
1921
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001922Handle<Code> CallStubCompiler::CompileMathFloorCall(
1923 Handle<Object> object,
1924 Handle<JSObject> holder,
1925 Handle<JSGlobalPropertyCell> cell,
1926 Handle<JSFunction> function,
1927 Handle<String> name) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001928 // TODO(872): implement this.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001929 return Handle<Code>::null();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001930}
1931
1932
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001933Handle<Code> CallStubCompiler::CompileMathAbsCall(
1934 Handle<Object> object,
1935 Handle<JSObject> holder,
1936 Handle<JSGlobalPropertyCell> cell,
1937 Handle<JSFunction> function,
1938 Handle<String> name) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001939 // ----------- S t a t e -------------
1940 // -- rcx : function name
1941 // -- rsp[0] : return address
1942 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1943 // -- ...
1944 // -- rsp[(argc + 1) * 8] : receiver
1945 // -----------------------------------
1946
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001947 // If the object is not a JSObject or we got an unexpected number of
1948 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001949 const int argc = arguments().immediate();
1950 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001951
1952 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001953 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001954
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001955 if (cell.is_null()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001956 __ movq(rdx, Operand(rsp, 2 * kPointerSize));
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001957 __ JumpIfSmi(rdx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001958 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
1959 name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001960 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001961 ASSERT(cell->value() == *function);
1962 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1963 &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001964 GenerateLoadFunctionFromCell(cell, function, &miss);
1965 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001966 // Load the (only) argument into rax.
1967 __ movq(rax, Operand(rsp, 1 * kPointerSize));
1968
1969 // Check if the argument is a smi.
1970 Label not_smi;
1971 STATIC_ASSERT(kSmiTag == 0);
1972 __ JumpIfNotSmi(rax, &not_smi);
1973 __ SmiToInteger32(rax, rax);
1974
1975 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
1976 // otherwise.
1977 __ movl(rbx, rax);
1978 __ sarl(rbx, Immediate(kBitsPerInt - 1));
1979
1980 // Do bitwise not or do nothing depending on ebx.
1981 __ xorl(rax, rbx);
1982
1983 // Add 1 or do nothing depending on ebx.
1984 __ subl(rax, rbx);
1985
1986 // If the result is still negative, go to the slow case.
1987 // This only happens for the most negative smi.
1988 Label slow;
1989 __ j(negative, &slow);
1990
1991 // Smi case done.
1992 __ Integer32ToSmi(rax, rax);
1993 __ ret(2 * kPointerSize);
1994
1995 // Check if the argument is a heap number and load its value.
1996 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001997 __ CheckMap(rax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001998 __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
1999
2000 // Check the sign of the argument. If the argument is positive,
2001 // just return it.
2002 Label negative_sign;
2003 const int sign_mask_shift =
2004 (HeapNumber::kExponentOffset - HeapNumber::kValueOffset) * kBitsPerByte;
2005 __ movq(rdi, static_cast<int64_t>(HeapNumber::kSignMask) << sign_mask_shift,
2006 RelocInfo::NONE);
2007 __ testq(rbx, rdi);
2008 __ j(not_zero, &negative_sign);
2009 __ ret(2 * kPointerSize);
2010
2011 // If the argument is negative, clear the sign, and return a new
2012 // number. We still have the sign mask in rdi.
2013 __ bind(&negative_sign);
2014 __ xor_(rbx, rdi);
2015 __ AllocateHeapNumber(rax, rdx, &slow);
2016 __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rbx);
2017 __ ret(2 * kPointerSize);
2018
2019 // Tail call the full function. We do not have to patch the receiver
2020 // because the function makes no use of it.
2021 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002022 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002023 ? CALL_AS_FUNCTION
2024 : CALL_AS_METHOD;
2025 __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2026 NullCallWrapper(), call_kind);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002027
2028 __ bind(&miss);
2029 // rcx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002030 GenerateMissBranch();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002031
2032 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002033 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002034}
2035
2036
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002037Handle<Code> CallStubCompiler::CompileFastApiCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002038 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002039 Handle<Object> object,
2040 Handle<JSObject> holder,
2041 Handle<JSGlobalPropertyCell> cell,
2042 Handle<JSFunction> function,
2043 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002044 ASSERT(optimization.is_simple_api_call());
2045 // Bail out if object is a global object as we don't want to
2046 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002047 if (object->IsGlobalObject()) return Handle<Code>::null();
2048 if (!cell.is_null()) return Handle<Code>::null();
2049 if (!object->IsJSObject()) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002051 Handle<JSObject>::cast(object), holder);
2052 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002053
2054 Label miss, miss_before_stack_reserved;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002055 GenerateNameCheck(name, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002056
2057 // Get the receiver from the stack.
2058 const int argc = arguments().immediate();
2059 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2060
2061 // Check that the receiver isn't a smi.
2062 __ JumpIfSmi(rdx, &miss_before_stack_reserved);
2063
lrn@chromium.org7516f052011-03-30 08:52:27 +00002064 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002065 __ IncrementCounter(counters->call_const(), 1);
2066 __ IncrementCounter(counters->call_const_fast_api(), 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002067
2068 // Allocate space for v8::Arguments implicit values. Must be initialized
2069 // before calling any runtime function.
2070 __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2071
2072 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002073 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
2074 name, depth, &miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002075
2076 // Move the return address on top of the stack.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002077 __ movq(rax, Operand(rsp, 4 * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002078 __ movq(Operand(rsp, 0 * kPointerSize), rax);
2079
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002080 GenerateFastApiCall(masm(), optimization, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002081
2082 __ bind(&miss);
2083 __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2084
2085 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002086 GenerateMissBranch();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002087
2088 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002089 return GetCode(function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002090}
2091
2092
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002093Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2094 Handle<JSObject> holder,
2095 Handle<JSFunction> function,
2096 Handle<String> name,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002097 CheckType check) {
2098 // ----------- S t a t e -------------
2099 // rcx : function name
2100 // rsp[0] : return address
2101 // rsp[8] : argument argc
2102 // rsp[16] : argument argc - 1
2103 // ...
2104 // rsp[argc * 8] : argument 1
2105 // rsp[(argc + 1) * 8] : argument 0 = receiver
2106 // -----------------------------------
2107
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002108 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002109 Handle<Code> code = CompileCustomCall(object, holder,
2110 Handle<JSGlobalPropertyCell>::null(),
2111 function, name);
2112 // A null handle means bail out to the regular compiler code below.
2113 if (!code.is_null()) return code;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002114 }
2115
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002116 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002117 GenerateNameCheck(name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002118
2119 // Get the receiver from the stack.
2120 const int argc = arguments().immediate();
2121 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2122
2123 // Check that the receiver isn't a smi.
2124 if (check != NUMBER_CHECK) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002125 __ JumpIfSmi(rdx, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002126 }
2127
2128 // Make sure that it's okay not to patch the on stack receiver
2129 // unless we're doing a receiver map check.
2130 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2131
lrn@chromium.org7516f052011-03-30 08:52:27 +00002132 Counters* counters = isolate()->counters();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002133 switch (check) {
2134 case RECEIVER_MAP_CHECK:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002135 __ IncrementCounter(counters->call_const(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002136
2137 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002138 CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax,
2139 rdi, name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002140
2141 // Patch the receiver on the stack with the global proxy if
2142 // necessary.
2143 if (object->IsGlobalObject()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002144 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
2145 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
2146 }
2147 break;
2148
2149 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002150 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002151 // Check that the object is a two-byte string or a symbol.
2152 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
2153 __ j(above_equal, &miss);
2154 // Check that the maps starting from the prototype haven't changed.
2155 GenerateDirectLoadGlobalFunctionPrototype(
2156 masm(), Context::STRING_FUNCTION_INDEX, rax, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002157 CheckPrototypes(
2158 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2159 rax, holder, rbx, rdx, rdi, name, &miss);
2160 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002161 // Calling non-strict non-builtins with a value as the receiver
2162 // requires boxing.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002163 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002164 }
2165 break;
2166
2167 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002168 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002169 Label fast;
2170 // Check that the object is a smi or a heap number.
2171 __ JumpIfSmi(rdx, &fast);
2172 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax);
2173 __ j(not_equal, &miss);
2174 __ bind(&fast);
2175 // Check that the maps starting from the prototype haven't changed.
2176 GenerateDirectLoadGlobalFunctionPrototype(
2177 masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002178 CheckPrototypes(
2179 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2180 rax, holder, rbx, rdx, rdi, name, &miss);
2181 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002182 // Calling non-strict non-builtins with a value as the receiver
2183 // requires boxing.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002184 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002185 }
2186 break;
2187
2188 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002189 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002190 Label fast;
2191 // Check that the object is a boolean.
2192 __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
2193 __ j(equal, &fast);
2194 __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
2195 __ j(not_equal, &miss);
2196 __ bind(&fast);
2197 // Check that the maps starting from the prototype haven't changed.
2198 GenerateDirectLoadGlobalFunctionPrototype(
2199 masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002200 CheckPrototypes(
2201 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2202 rax, holder, rbx, rdx, rdi, name, &miss);
2203 } else {
2204 // Calling non-strict non-builtins with a value as the receiver
2205 // requires boxing.
2206 __ jmp(&miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002207 }
2208 break;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002209 }
2210
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002211 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002212 ? CALL_AS_FUNCTION
2213 : CALL_AS_METHOD;
2214 __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2215 NullCallWrapper(), call_kind);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002216
2217 // Handle call cache miss.
2218 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002219 GenerateMissBranch();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002220
2221 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002222 return GetCode(function);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002223}
2224
2225
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002226Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2227 Handle<JSObject> holder,
2228 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002229 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00002230 // rcx : function name
2231 // rsp[0] : return address
2232 // rsp[8] : argument argc
2233 // rsp[16] : argument argc - 1
2234 // ...
2235 // rsp[argc * 8] : argument 1
2236 // rsp[(argc + 1) * 8] : argument 0 = receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002237 // -----------------------------------
2238 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002239 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002240
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002241 // Get the number of arguments.
2242 const int argc = arguments().immediate();
2243
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002244 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002245 LookupPostInterceptor(holder, name, &lookup);
2246
2247 // Get the receiver from the stack.
2248 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2249
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002250 CallInterceptorCompiler compiler(this, arguments(), rcx, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002251 compiler.Compile(masm(), object, holder, name, &lookup, rdx, rbx, rdi, rax,
2252 &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002253
2254 // Restore receiver.
2255 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2256
2257 // Check that the function really is a function.
ager@chromium.org4af710e2009-09-15 12:20:11 +00002258 __ JumpIfSmi(rax, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002259 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2260 __ j(not_equal, &miss);
2261
2262 // Patch the receiver on the stack with the global proxy if
2263 // necessary.
2264 if (object->IsGlobalObject()) {
2265 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
2266 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
2267 }
2268
2269 // Invoke the function.
2270 __ movq(rdi, rax);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002271 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002272 ? CALL_AS_FUNCTION
2273 : CALL_AS_METHOD;
2274 __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
2275 NullCallWrapper(), call_kind);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002276
2277 // Handle load cache miss.
2278 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002279 GenerateMissBranch();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002280
2281 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002282 return GetCode(Code::INTERCEPTOR, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002283}
2284
2285
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002286Handle<Code> CallStubCompiler::CompileCallGlobal(
2287 Handle<JSObject> object,
2288 Handle<GlobalObject> holder,
2289 Handle<JSGlobalPropertyCell> cell,
2290 Handle<JSFunction> function,
2291 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002292 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00002293 // rcx : function name
2294 // rsp[0] : return address
2295 // rsp[8] : argument argc
2296 // rsp[16] : argument argc - 1
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002297 // ...
ager@chromium.org5c838252010-02-19 08:53:10 +00002298 // rsp[argc * 8] : argument 1
2299 // rsp[(argc + 1) * 8] : argument 0 = receiver
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002300 // -----------------------------------
2301
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002302 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002303 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2304 // A null handle means bail out to the regular compiler code below.
2305 if (!code.is_null()) return code;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002306 }
2307
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002308 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002309 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002310
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002311 // Get the number of arguments.
2312 const int argc = arguments().immediate();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002313 GenerateGlobalReceiverCheck(object, holder, name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002314 GenerateLoadFunctionFromCell(cell, function, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002315
2316 // Patch the receiver on the stack with the global proxy.
2317 if (object->IsGlobalObject()) {
2318 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
2319 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
2320 }
2321
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002322 // Set up the context (function already in rdi).
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002323 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
2324
2325 // Jump to the cached code (tail call).
lrn@chromium.org7516f052011-03-30 08:52:27 +00002326 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002327 __ IncrementCounter(counters->call_global_inline(), 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002328 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002329 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002330 ? CALL_AS_FUNCTION
2331 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002332 // We call indirectly through the code field in the function to
2333 // allow recompilation to take effect without changing any of the
2334 // call sites.
2335 __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
2336 __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION,
2337 NullCallWrapper(), call_kind);
2338
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002339 // Handle call cache miss.
2340 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002341 __ IncrementCounter(counters->call_global_inline_miss(), 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002342 GenerateMissBranch();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002343
2344 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002345 return GetCode(Code::NORMAL, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002346}
2347
2348
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002349Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002350 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002351 Handle<Map> transition,
2352 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002353 // ----------- S t a t e -------------
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002354 // -- rax : value
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002355 // -- rcx : name
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002356 // -- rdx : receiver
2357 // -- rsp[0] : return address
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002358 // -----------------------------------
2359 Label miss;
2360
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002361 // Generate store field code. Preserves receiver and name on jump to miss.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002362 GenerateStoreField(masm(),
2363 object,
2364 index,
2365 transition,
2366 name,
2367 rdx, rcx, rbx, rdi,
2368 &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002369
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002370 // Handle store cache miss.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002371 __ bind(&miss);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002372 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002373 __ Jump(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002374
2375 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002376 return GetCode(transition.is_null()
2377 ? Code::FIELD
2378 : Code::MAP_TRANSITION, name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002379}
2380
2381
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002382Handle<Code> StoreStubCompiler::CompileStoreCallback(
2383 Handle<JSObject> object,
2384 Handle<AccessorInfo> callback,
2385 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002386 // ----------- S t a t e -------------
2387 // -- rax : value
2388 // -- rcx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002389 // -- rdx : receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002390 // -- rsp[0] : return address
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002391 // -----------------------------------
2392 Label miss;
2393
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002394 // Check that the map of the object hasn't changed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002395 __ CheckMap(rdx, Handle<Map>(object->map()), &miss,
2396 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002397
2398 // Perform global security token check if needed.
2399 if (object->IsJSGlobalProxy()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002400 __ CheckAccessGlobalProxy(rdx, rbx, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002401 }
2402
2403 // Stub never generated for non-global objects that require access
2404 // checks.
2405 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2406
2407 __ pop(rbx); // remove the return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002408 __ push(rdx); // receiver
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002409 __ Push(callback); // callback info
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002410 __ push(rcx); // name
2411 __ push(rax); // value
2412 __ push(rbx); // restore return address
2413
2414 // Do tail-call to the runtime system.
2415 ExternalReference store_callback_property =
lrn@chromium.org7516f052011-03-30 08:52:27 +00002416 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002417 __ TailCallExternalReference(store_callback_property, 4, 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002418
2419 // Handle store cache miss.
2420 __ bind(&miss);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002421 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002422 __ Jump(ic, RelocInfo::CODE_TARGET);
2423
2424 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002425 return GetCode(Code::CALLBACKS, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002426}
2427
2428
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002429Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002430 Handle<String> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002431 Handle<JSObject> receiver,
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002432 Handle<JSObject> holder,
2433 Handle<JSFunction> setter) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002434 // ----------- S t a t e -------------
2435 // -- rax : value
2436 // -- rcx : name
2437 // -- rdx : receiver
2438 // -- rsp[0] : return address
2439 // -----------------------------------
2440 Label miss;
2441
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002442 // Check that the maps haven't changed.
2443 __ JumpIfSmi(rdx, &miss);
2444 CheckPrototypes(receiver, rdx, holder, rbx, r8, rdi, name, &miss);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002445
2446 {
2447 FrameScope scope(masm(), StackFrame::INTERNAL);
2448
2449 // Save value register, so we can restore it later.
2450 __ push(rax);
2451
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002452 // Call the JavaScript setter with the receiver and the value on the stack.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002453 __ push(rdx);
2454 __ push(rax);
2455 ParameterCount actual(1);
2456 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2457 CALL_AS_METHOD);
2458
2459 // We have to return the passed value, not the return value of the setter.
2460 __ pop(rax);
2461
2462 // Restore context register.
2463 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2464 }
2465 __ ret(0);
2466
2467 __ bind(&miss);
2468 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2469 __ Jump(ic, RelocInfo::CODE_TARGET);
2470
2471 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002472 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002473}
2474
2475
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002476Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2477 Handle<JSObject> receiver,
2478 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002479 // ----------- S t a t e -------------
2480 // -- rax : value
2481 // -- rcx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002482 // -- rdx : receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002483 // -- rsp[0] : return address
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002484 // -----------------------------------
2485 Label miss;
2486
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002487 // Check that the map of the object hasn't changed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002488 __ CheckMap(rdx, Handle<Map>(receiver->map()), &miss,
2489 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002490
2491 // Perform global security token check if needed.
2492 if (receiver->IsJSGlobalProxy()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002493 __ CheckAccessGlobalProxy(rdx, rbx, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002494 }
2495
2496 // Stub never generated for non-global objects that require access
2497 // checks.
2498 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2499
2500 __ pop(rbx); // remove the return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002501 __ push(rdx); // receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002502 __ push(rcx); // name
2503 __ push(rax); // value
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002504 __ Push(Smi::FromInt(strict_mode_));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002505 __ push(rbx); // restore return address
2506
2507 // Do tail-call to the runtime system.
2508 ExternalReference store_ic_property =
lrn@chromium.org7516f052011-03-30 08:52:27 +00002509 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002510 __ TailCallExternalReference(store_ic_property, 4, 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002511
2512 // Handle store cache miss.
2513 __ bind(&miss);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002514 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002515 __ Jump(ic, RelocInfo::CODE_TARGET);
2516
2517 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002518 return GetCode(Code::INTERCEPTOR, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002519}
2520
2521
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002522Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2523 Handle<GlobalObject> object,
2524 Handle<JSGlobalPropertyCell> cell,
2525 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002526 // ----------- S t a t e -------------
2527 // -- rax : value
2528 // -- rcx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002529 // -- rdx : receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002530 // -- rsp[0] : return address
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002531 // -----------------------------------
2532 Label miss;
2533
2534 // Check that the map of the global has not changed.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002535 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002536 Handle<Map>(object->map()));
2537 __ j(not_equal, &miss);
2538
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002539 // Compute the cell operand to use.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002540 __ Move(rbx, cell);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002541 Operand cell_operand = FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset);
2542
ager@chromium.org378b34e2011-01-28 08:04:38 +00002543 // Check that the value in the cell is not the hole. If it is, this
2544 // cell could have been deleted and reintroducing the global needs
2545 // to update the property details in the property dictionary of the
2546 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002547 __ CompareRoot(cell_operand, Heap::kTheHoleValueRootIndex);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002548 __ j(equal, &miss);
2549
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002550 // Store the value in the cell.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002551 __ movq(cell_operand, rax);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002552 // Cells are always rescanned, so no write barrier here.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002553
2554 // Return the value (register rax).
lrn@chromium.org7516f052011-03-30 08:52:27 +00002555 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002556 __ IncrementCounter(counters->named_store_global_inline(), 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002557 __ ret(0);
2558
2559 // Handle store cache miss.
2560 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002561 __ IncrementCounter(counters->named_store_global_inline_miss(), 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002562 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002563 __ Jump(ic, RelocInfo::CODE_TARGET);
2564
2565 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002566 return GetCode(Code::NORMAL, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002567}
2568
2569
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002570Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002571 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002572 Handle<Map> transition,
2573 Handle<String> name) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002574 // ----------- S t a t e -------------
2575 // -- rax : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002576 // -- rcx : key
2577 // -- rdx : receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002578 // -- rsp[0] : return address
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002579 // -----------------------------------
2580 Label miss;
2581
lrn@chromium.org7516f052011-03-30 08:52:27 +00002582 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002583 __ IncrementCounter(counters->keyed_store_field(), 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002584
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002585 // Check that the name has not changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002586 __ Cmp(rcx, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002587 __ j(not_equal, &miss);
2588
ager@chromium.org5c838252010-02-19 08:53:10 +00002589 // Generate store field code. Preserves receiver and name on jump to miss.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002590 GenerateStoreField(masm(),
2591 object,
2592 index,
2593 transition,
2594 name,
2595 rdx, rcx, rbx, rdi,
2596 &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002597
2598 // Handle store cache miss.
2599 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002600 __ DecrementCounter(counters->keyed_store_field(), 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002601 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002602 __ Jump(ic, RelocInfo::CODE_TARGET);
2603
2604 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002605 return GetCode(transition.is_null()
2606 ? Code::FIELD
2607 : Code::MAP_TRANSITION, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002608}
2609
2610
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002611Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
2612 Handle<Map> receiver_map) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002613 // ----------- S t a t e -------------
2614 // -- rax : value
2615 // -- rcx : key
2616 // -- rdx : receiver
2617 // -- rsp[0] : return address
2618 // -----------------------------------
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002619
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002620 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002621 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002622 Handle<Code> stub =
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002623 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002624
2625 __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002626
2627 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
2628 __ jmp(ic, RelocInfo::CODE_TARGET);
2629
2630 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002631 return GetCode(Code::NORMAL, factory()->empty_string());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002632}
2633
2634
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002635Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2636 MapHandleList* receiver_maps,
2637 CodeHandleList* handler_stubs,
2638 MapHandleList* transitioned_maps) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002639 // ----------- S t a t e -------------
2640 // -- rax : value
2641 // -- rcx : key
2642 // -- rdx : receiver
2643 // -- rsp[0] : return address
2644 // -----------------------------------
2645 Label miss;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002646 __ JumpIfSmi(rdx, &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002647
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002648 __ movq(rdi, FieldOperand(rdx, HeapObject::kMapOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002649 int receiver_count = receiver_maps->length();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002650 for (int i = 0; i < receiver_count; ++i) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002651 // Check map and tail call if there's a match
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002652 __ Cmp(rdi, receiver_maps->at(i));
2653 if (transitioned_maps->at(i).is_null()) {
2654 __ j(equal, handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002655 } else {
2656 Label next_map;
2657 __ j(not_equal, &next_map, Label::kNear);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002658 __ movq(rbx, transitioned_maps->at(i), RelocInfo::EMBEDDED_OBJECT);
2659 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002660 __ bind(&next_map);
2661 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002662 }
2663
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002664 __ bind(&miss);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002665 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002666 __ jmp(ic, RelocInfo::CODE_TARGET);
2667
2668 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002669 return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002670}
2671
2672
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002673Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2674 Handle<JSObject> object,
2675 Handle<JSObject> last) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002676 // ----------- S t a t e -------------
2677 // -- rax : receiver
2678 // -- rcx : name
2679 // -- rsp[0] : return address
2680 // -----------------------------------
2681 Label miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002682
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002683 // Check that receiver is not a smi.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002684 __ JumpIfSmi(rax, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002685
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002686 // Check the maps of the full prototype chain. Also check that
2687 // global property cells up to (but not including) the last object
2688 // in the prototype chain are empty.
2689 CheckPrototypes(object, rax, last, rbx, rdx, rdi, name, &miss);
2690
2691 // If the last object in the prototype chain is a global object,
2692 // check that the global property cell is empty.
2693 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002694 GenerateCheckPropertyCell(
2695 masm(), Handle<GlobalObject>::cast(last), name, rdx, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002696 }
2697
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002698 // Return undefined if maps of the full prototype chain are still the
2699 // same and no global property with this name contains a value.
2700 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2701 __ ret(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002702
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002703 __ bind(&miss);
2704 GenerateLoadMiss(masm(), Code::LOAD_IC);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002705
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002706 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002707 return GetCode(Code::NONEXISTENT, factory()->empty_string());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002708}
2709
2710
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002711Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2712 Handle<JSObject> holder,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002713 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002714 Handle<String> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002715 // ----------- S t a t e -------------
2716 // -- rax : receiver
2717 // -- rcx : name
2718 // -- rsp[0] : return address
2719 // -----------------------------------
2720 Label miss;
2721
2722 GenerateLoadField(object, holder, rax, rbx, rdx, rdi, index, name, &miss);
2723 __ bind(&miss);
2724 GenerateLoadMiss(masm(), Code::LOAD_IC);
2725
2726 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002727 return GetCode(Code::FIELD, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002728}
2729
2730
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002731Handle<Code> LoadStubCompiler::CompileLoadCallback(
2732 Handle<String> name,
2733 Handle<JSObject> object,
2734 Handle<JSObject> holder,
2735 Handle<AccessorInfo> callback) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002736 // ----------- S t a t e -------------
2737 // -- rax : receiver
2738 // -- rcx : name
2739 // -- rsp[0] : return address
2740 // -----------------------------------
2741 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002742 GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, rdi, callback,
2743 name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002744 __ bind(&miss);
2745 GenerateLoadMiss(masm(), Code::LOAD_IC);
2746
2747 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002748 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002749}
2750
2751
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002752Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
2753 Handle<String> name,
2754 Handle<JSObject> receiver,
2755 Handle<JSObject> holder,
2756 Handle<JSFunction> getter) {
2757 // ----------- S t a t e -------------
2758 // -- rax : receiver
2759 // -- rcx : name
2760 // -- rsp[0] : return address
2761 // -----------------------------------
2762 Label miss;
2763
2764 // Check that the maps haven't changed.
2765 __ JumpIfSmi(rax, &miss);
2766 CheckPrototypes(receiver, rax, holder, rbx, rdx, rdi, name, &miss);
2767
2768 {
2769 FrameScope scope(masm(), StackFrame::INTERNAL);
2770
2771 // Call the JavaScript getter with the receiver on the stack.
2772 __ push(rax);
2773 ParameterCount actual(0);
2774 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
2775 CALL_AS_METHOD);
2776
2777 // Restore context register.
2778 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2779 }
2780 __ ret(0);
2781
2782 __ bind(&miss);
2783 GenerateLoadMiss(masm(), Code::LOAD_IC);
2784
2785 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002786 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002787}
2788
2789
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002790Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2791 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002792 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002793 Handle<String> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002794 // ----------- S t a t e -------------
2795 // -- rax : receiver
2796 // -- rcx : name
2797 // -- rsp[0] : return address
2798 // -----------------------------------
2799 Label miss;
2800
2801 GenerateLoadConstant(object, holder, rax, rbx, rdx, rdi, value, name, &miss);
2802 __ bind(&miss);
2803 GenerateLoadMiss(masm(), Code::LOAD_IC);
2804
2805 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002806 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002807}
2808
2809
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002810Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> receiver,
2811 Handle<JSObject> holder,
2812 Handle<String> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002813 // ----------- S t a t e -------------
2814 // -- rax : receiver
2815 // -- rcx : name
2816 // -- rsp[0] : return address
2817 // -----------------------------------
2818 Label miss;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002819 LookupResult lookup(isolate());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002820 LookupPostInterceptor(holder, name, &lookup);
2821
2822 // TODO(368): Compile in the whole chain: all the interceptors in
2823 // prototypes and ultimate answer.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002824 GenerateLoadInterceptor(receiver, holder, &lookup, rax, rcx, rdx, rbx, rdi,
2825 name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002826 __ bind(&miss);
2827 GenerateLoadMiss(masm(), Code::LOAD_IC);
2828
2829 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002830 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002831}
2832
2833
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002834Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2835 Handle<JSObject> object,
2836 Handle<GlobalObject> holder,
2837 Handle<JSGlobalPropertyCell> cell,
2838 Handle<String> name,
2839 bool is_dont_delete) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002840 // ----------- S t a t e -------------
2841 // -- rax : receiver
2842 // -- rcx : name
2843 // -- rsp[0] : return address
2844 // -----------------------------------
2845 Label miss;
2846
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002847 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00002848 __ JumpIfSmi(rax, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002849 CheckPrototypes(object, rax, holder, rbx, rdx, rdi, name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002850
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002851 // Get the value from the cell.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002852 __ Move(rbx, cell);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002853 __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset));
whesse@chromium.orge90029b2010-08-02 11:52:17 +00002854
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002855 // Check for deleted property if property can actually be deleted.
2856 if (!is_dont_delete) {
2857 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
2858 __ j(equal, &miss);
2859 } else if (FLAG_debug_code) {
2860 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
2861 __ Check(not_equal, "DontDelete cells can't contain the hole");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002862 }
2863
lrn@chromium.org7516f052011-03-30 08:52:27 +00002864 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002865 __ IncrementCounter(counters->named_load_global_stub(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002866 __ movq(rax, rbx);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002867 __ ret(0);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002868
2869 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002870 __ IncrementCounter(counters->named_load_global_stub_miss(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002871 GenerateLoadMiss(masm(), Code::LOAD_IC);
2872
2873 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002874 return GetCode(Code::NORMAL, name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002875}
2876
2877
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002878Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
2879 Handle<JSObject> receiver,
2880 Handle<JSObject> holder,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002881 int index) {
2882 // ----------- S t a t e -------------
2883 // -- rax : key
2884 // -- rdx : receiver
2885 // -- rsp[0] : return address
2886 // -----------------------------------
2887 Label miss;
2888
lrn@chromium.org7516f052011-03-30 08:52:27 +00002889 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002890 __ IncrementCounter(counters->keyed_load_field(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002891
2892 // Check that the name has not changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002893 __ Cmp(rax, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002894 __ j(not_equal, &miss);
2895
2896 GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss);
2897
2898 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002899 __ DecrementCounter(counters->keyed_load_field(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002900 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2901
2902 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002903 return GetCode(Code::FIELD, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002904}
2905
2906
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002907Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
2908 Handle<String> name,
2909 Handle<JSObject> receiver,
2910 Handle<JSObject> holder,
2911 Handle<AccessorInfo> callback) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002912 // ----------- S t a t e -------------
2913 // -- rax : key
2914 // -- rdx : receiver
2915 // -- rsp[0] : return address
2916 // -----------------------------------
2917 Label miss;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002918 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002919 __ IncrementCounter(counters->keyed_load_callback(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002920
2921 // Check that the name has not changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002922 __ Cmp(rax, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002923 __ j(not_equal, &miss);
2924
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002925 GenerateLoadCallback(receiver, holder, rdx, rax, rbx, rcx, rdi, callback,
2926 name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002927 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002928 __ DecrementCounter(counters->keyed_load_callback(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002929 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2930
2931 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002932 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002933}
2934
2935
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002936Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
2937 Handle<String> name,
2938 Handle<JSObject> receiver,
2939 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002940 Handle<JSFunction> value) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002941 // ----------- S t a t e -------------
2942 // -- rax : key
2943 // -- rdx : receiver
2944 // -- rsp[0] : return address
2945 // -----------------------------------
2946 Label miss;
2947
lrn@chromium.org7516f052011-03-30 08:52:27 +00002948 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002949 __ IncrementCounter(counters->keyed_load_constant_function(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002950
2951 // Check that the name has not changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002952 __ Cmp(rax, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002953 __ j(not_equal, &miss);
2954
2955 GenerateLoadConstant(receiver, holder, rdx, rbx, rcx, rdi,
2956 value, name, &miss);
2957 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002958 __ DecrementCounter(counters->keyed_load_constant_function(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002959 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2960
2961 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002962 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002963}
2964
2965
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002966Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
2967 Handle<JSObject> receiver,
2968 Handle<JSObject> holder,
2969 Handle<String> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002970 // ----------- S t a t e -------------
2971 // -- rax : key
2972 // -- rdx : receiver
2973 // -- rsp[0] : return address
2974 // -----------------------------------
2975 Label miss;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002976 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002977 __ IncrementCounter(counters->keyed_load_interceptor(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002978
2979 // Check that the name has not changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002980 __ Cmp(rax, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002981 __ j(not_equal, &miss);
2982
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002983 LookupResult lookup(isolate());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002984 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002985 GenerateLoadInterceptor(receiver, holder, &lookup, rdx, rax, rcx, rbx, rdi,
2986 name, &miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002987 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002988 __ DecrementCounter(counters->keyed_load_interceptor(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002989 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2990
2991 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002992 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002993}
2994
2995
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002996Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
2997 Handle<String> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002998 // ----------- S t a t e -------------
2999 // -- rax : key
3000 // -- rdx : receiver
3001 // -- rsp[0] : return address
3002 // -----------------------------------
3003 Label miss;
3004
lrn@chromium.org7516f052011-03-30 08:52:27 +00003005 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003006 __ IncrementCounter(counters->keyed_load_array_length(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003007
3008 // Check that the name has not changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003009 __ Cmp(rax, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003010 __ j(not_equal, &miss);
3011
3012 GenerateLoadArrayLength(masm(), rdx, rcx, &miss);
3013 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003014 __ DecrementCounter(counters->keyed_load_array_length(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003015 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3016
3017 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003018 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003019}
3020
3021
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003022Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
3023 Handle<String> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003024 // ----------- S t a t e -------------
3025 // -- rax : key
3026 // -- rdx : receiver
3027 // -- rsp[0] : return address
3028 // -----------------------------------
3029 Label miss;
3030
lrn@chromium.org7516f052011-03-30 08:52:27 +00003031 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003032 __ IncrementCounter(counters->keyed_load_string_length(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003033
3034 // Check that the name has not changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003035 __ Cmp(rax, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003036 __ j(not_equal, &miss);
3037
ager@chromium.org378b34e2011-01-28 08:04:38 +00003038 GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss, true);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003039 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003040 __ DecrementCounter(counters->keyed_load_string_length(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003041 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3042
3043 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003044 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003045}
3046
3047
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003048Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
3049 Handle<String> name) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003050 // ----------- S t a t e -------------
3051 // -- rax : key
3052 // -- rdx : receiver
3053 // -- rsp[0] : return address
3054 // -----------------------------------
3055 Label miss;
3056
lrn@chromium.org7516f052011-03-30 08:52:27 +00003057 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003058 __ IncrementCounter(counters->keyed_load_function_prototype(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003059
3060 // Check that the name has not changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003061 __ Cmp(rax, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003062 __ j(not_equal, &miss);
3063
3064 GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss);
3065 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003066 __ DecrementCounter(counters->keyed_load_function_prototype(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003067 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3068
3069 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003070 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003071}
3072
3073
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003074Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3075 Handle<Map> receiver_map) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003076 // ----------- S t a t e -------------
3077 // -- rax : key
3078 // -- rdx : receiver
3079 // -- rsp[0] : return address
3080 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003081 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003082 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3083
3084 __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003085
3086 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3087 __ jmp(ic, RelocInfo::CODE_TARGET);
3088
3089 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003090 return GetCode(Code::NORMAL, factory()->empty_string());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003091}
3092
3093
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003094Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3095 MapHandleList* receiver_maps,
3096 CodeHandleList* handler_ics) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003097 // ----------- S t a t e -------------
3098 // -- rax : key
3099 // -- rdx : receiver
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003100 // -- rsp[0] : return address
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003101 // -----------------------------------
3102 Label miss;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003103 __ JumpIfSmi(rdx, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003104
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003105 Register map_reg = rbx;
3106 __ movq(map_reg, FieldOperand(rdx, HeapObject::kMapOffset));
3107 int receiver_count = receiver_maps->length();
3108 for (int current = 0; current < receiver_count; ++current) {
3109 // Check map and tail call if there's a match
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003110 __ Cmp(map_reg, receiver_maps->at(current));
3111 __ j(equal, handler_ics->at(current), RelocInfo::CODE_TARGET);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003112 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003113
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003114 __ bind(&miss);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003115 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3116
3117 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003118 return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003119}
3120
3121
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003122// Specialized stub for constructing objects from functions which only have only
3123// simple assignments of the form this.x = ...; in their body.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003124Handle<Code> ConstructStubCompiler::CompileConstructStub(
3125 Handle<JSFunction> function) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003126 // ----------- S t a t e -------------
3127 // -- rax : argc
3128 // -- rdi : constructor
3129 // -- rsp[0] : return address
3130 // -- rsp[4] : last argument
3131 // -----------------------------------
3132 Label generic_stub_call;
3133
3134 // Use r8 for holding undefined which is used in several places below.
lrn@chromium.org7516f052011-03-30 08:52:27 +00003135 __ Move(r8, factory()->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003136
3137#ifdef ENABLE_DEBUGGER_SUPPORT
3138 // Check to see whether there are any break points in the function code. If
3139 // there are jump to the generic constructor stub which calls the actual
3140 // code for the function thereby hitting the break points.
3141 __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
3142 __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kDebugInfoOffset));
3143 __ cmpq(rbx, r8);
3144 __ j(not_equal, &generic_stub_call);
3145#endif
3146
3147 // Load the initial map and verify that it is in fact a map.
3148 __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
3149 // Will both indicate a NULL and a Smi.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003150 STATIC_ASSERT(kSmiTag == 0);
ager@chromium.org4af710e2009-09-15 12:20:11 +00003151 __ JumpIfSmi(rbx, &generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003152 __ CmpObjectType(rbx, MAP_TYPE, rcx);
3153 __ j(not_equal, &generic_stub_call);
3154
3155#ifdef DEBUG
3156 // Cannot construct functions this way.
3157 // rdi: constructor
3158 // rbx: initial map
3159 __ CmpInstanceType(rbx, JS_FUNCTION_TYPE);
3160 __ Assert(not_equal, "Function constructed by construct stub.");
3161#endif
3162
3163 // Now allocate the JSObject in new space.
3164 // rdi: constructor
3165 // rbx: initial map
3166 __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset));
3167 __ shl(rcx, Immediate(kPointerSizeLog2));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003168 __ AllocateInNewSpace(rcx, rdx, rcx, no_reg,
3169 &generic_stub_call, NO_ALLOCATION_FLAGS);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003170
3171 // Allocated the JSObject, now initialize the fields and add the heap tag.
3172 // rbx: initial map
3173 // rdx: JSObject (untagged)
3174 __ movq(Operand(rdx, JSObject::kMapOffset), rbx);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003175 __ Move(rbx, factory()->empty_fixed_array());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003176 __ movq(Operand(rdx, JSObject::kPropertiesOffset), rbx);
3177 __ movq(Operand(rdx, JSObject::kElementsOffset), rbx);
3178
3179 // rax: argc
3180 // rdx: JSObject (untagged)
3181 // Load the address of the first in-object property into r9.
3182 __ lea(r9, Operand(rdx, JSObject::kHeaderSize));
3183 // Calculate the location of the first argument. The stack contains only the
3184 // return address on top of the argc arguments.
3185 __ lea(rcx, Operand(rsp, rax, times_pointer_size, 0));
3186
3187 // rax: argc
3188 // rcx: first argument
3189 // rdx: JSObject (untagged)
3190 // r8: undefined
3191 // r9: first in-object property of the JSObject
3192 // Fill the initialized properties with a constant value or a passed argument
3193 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003194 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003195 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3196 if (shared->IsThisPropertyAssignmentArgument(i)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003197 // Check if the argument assigned to the property is actually passed.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003198 // If argument is not passed the property is set to undefined,
3199 // otherwise find it on the stack.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003200 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003201 __ movq(rbx, r8);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003202 __ cmpq(rax, Immediate(arg_number));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003203 __ cmovq(above, rbx, Operand(rcx, arg_number * -kPointerSize));
3204 // Store value in the property.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003205 __ movq(Operand(r9, i * kPointerSize), rbx);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003206 } else {
3207 // Set the property to the constant value.
3208 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3209 __ Move(Operand(r9, i * kPointerSize), constant);
3210 }
3211 }
3212
3213 // Fill the unused in-object property fields with undefined.
ager@chromium.orgbeb25712010-11-29 08:02:25 +00003214 ASSERT(function->has_initial_map());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003215 for (int i = shared->this_property_assignments_count();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00003216 i < function->initial_map()->inobject_properties();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003217 i++) {
3218 __ movq(Operand(r9, i * kPointerSize), r8);
3219 }
3220
3221 // rax: argc
3222 // rdx: JSObject (untagged)
3223 // Move argc to rbx and the JSObject to return to rax and tag it.
3224 __ movq(rbx, rax);
3225 __ movq(rax, rdx);
3226 __ or_(rax, Immediate(kHeapObjectTag));
3227
3228 // rax: JSObject
3229 // rbx: argc
3230 // Remove caller arguments and receiver from the stack and return.
3231 __ pop(rcx);
3232 __ lea(rsp, Operand(rsp, rbx, times_pointer_size, 1 * kPointerSize));
3233 __ push(rcx);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003234 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003235 __ IncrementCounter(counters->constructed_objects(), 1);
3236 __ IncrementCounter(counters->constructed_objects_stub(), 1);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003237 __ ret(0);
3238
3239 // Jump to the generic stub in case the specialized code cannot handle the
3240 // construction.
3241 __ bind(&generic_stub_call);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003242 Handle<Code> code = isolate()->builtins()->JSConstructStubGeneric();
3243 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003244
3245 // Return the generated code.
3246 return GetCode();
3247}
3248
3249
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003250#undef __
3251#define __ ACCESS_MASM(masm)
3252
3253
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003254void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3255 MacroAssembler* masm) {
3256 // ----------- S t a t e -------------
3257 // -- rax : key
3258 // -- rdx : receiver
3259 // -- rsp[0] : return address
3260 // -----------------------------------
3261 Label slow, miss_force_generic;
3262
3263 // This stub is meant to be tail-jumped to, the receiver must already
3264 // have been verified by the caller to not be a smi.
3265
3266 __ JumpIfNotSmi(rax, &miss_force_generic);
3267 __ SmiToInteger32(rbx, rax);
3268 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
3269
3270 // Check whether the elements is a number dictionary.
3271 // rdx: receiver
3272 // rax: key
3273 // rbx: key as untagged int32
3274 // rcx: elements
3275 __ LoadFromNumberDictionary(&slow, rcx, rax, rbx, r9, rdi, rax);
3276 __ ret(0);
3277
3278 __ bind(&slow);
3279 // ----------- S t a t e -------------
3280 // -- rax : key
3281 // -- rdx : receiver
3282 // -- rsp[0] : return address
3283 // -----------------------------------
3284 Handle<Code> slow_ic =
3285 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3286 __ jmp(slow_ic, RelocInfo::CODE_TARGET);
3287
3288 __ bind(&miss_force_generic);
3289 // ----------- S t a t e -------------
3290 // -- rax : key
3291 // -- rdx : receiver
3292 // -- rsp[0] : return address
3293 // -----------------------------------
3294 Handle<Code> miss_ic =
3295 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3296 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
3297}
3298
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003299
3300static void GenerateSmiKeyCheck(MacroAssembler* masm,
3301 Register key,
3302 Register scratch,
3303 XMMRegister xmm_scratch0,
3304 XMMRegister xmm_scratch1,
3305 Label* fail) {
3306 // Check that key is a smi or a heap number containing a smi and branch
3307 // if the check fails.
3308 Label key_ok;
3309 __ JumpIfSmi(key, &key_ok);
3310 __ CheckMap(key,
3311 masm->isolate()->factory()->heap_number_map(),
3312 fail,
3313 DONT_DO_SMI_CHECK);
3314 __ movsd(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset));
3315 __ cvttsd2si(scratch, xmm_scratch0);
3316 __ cvtlsi2sd(xmm_scratch1, scratch);
3317 __ ucomisd(xmm_scratch1, xmm_scratch0);
3318 __ j(not_equal, fail);
3319 __ j(parity_even, fail); // NaN.
3320 __ Integer32ToSmi(key, scratch);
3321 __ bind(&key_ok);
3322}
3323
3324
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003325void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3326 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003327 ElementsKind elements_kind) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003328 // ----------- S t a t e -------------
3329 // -- rax : key
3330 // -- rdx : receiver
3331 // -- rsp[0] : return address
3332 // -----------------------------------
3333 Label slow, miss_force_generic;
3334
3335 // This stub is meant to be tail-jumped to, the receiver must already
3336 // have been verified by the caller to not be a smi.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003337
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003338 // Check that the key is a smi or a heap number convertible to a smi.
3339 GenerateSmiKeyCheck(masm, rax, rcx, xmm0, xmm1, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003340
3341 // Check that the index is in range.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003342 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
danno@chromium.orgb6451162011-08-17 14:33:23 +00003343 __ SmiToInteger32(rcx, rax);
3344 __ cmpq(rax, FieldOperand(rbx, ExternalArray::kLengthOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003345 // Unsigned comparison catches both negative and too-large values.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003346 __ j(above_equal, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003347
3348 // rax: index (as a smi)
3349 // rdx: receiver (JSObject)
3350 // rcx: untagged index
3351 // rbx: elements array
3352 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
3353 // rbx: base pointer of external storage
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003354 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003355 case EXTERNAL_BYTE_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003356 __ movsxbq(rcx, Operand(rbx, rcx, times_1, 0));
3357 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003358 case EXTERNAL_PIXEL_ELEMENTS:
3359 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003360 __ movzxbq(rcx, Operand(rbx, rcx, times_1, 0));
3361 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003362 case EXTERNAL_SHORT_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003363 __ movsxwq(rcx, Operand(rbx, rcx, times_2, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003364 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003365 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003366 __ movzxwq(rcx, Operand(rbx, rcx, times_2, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003367 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003368 case EXTERNAL_INT_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003369 __ movsxlq(rcx, Operand(rbx, rcx, times_4, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003370 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003371 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003372 __ movl(rcx, Operand(rbx, rcx, times_4, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003373 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003374 case EXTERNAL_FLOAT_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003375 __ cvtss2sd(xmm0, Operand(rbx, rcx, times_4, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003376 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003377 case EXTERNAL_DOUBLE_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003378 __ movsd(xmm0, Operand(rbx, rcx, times_8, 0));
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003379 break;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003380 default:
3381 UNREACHABLE();
3382 break;
3383 }
3384
3385 // rax: index
3386 // rdx: receiver
3387 // For integer array types:
3388 // rcx: value
3389 // For floating-point array type:
3390 // xmm0: value as double.
3391
3392 ASSERT(kSmiValueSize == 32);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003393 if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003394 // For the UnsignedInt array type, we need to see whether
3395 // the value can be represented in a Smi. If not, we need to convert
3396 // it to a HeapNumber.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003397 Label box_int;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003398
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003399 __ JumpIfUIntNotValidSmiValue(rcx, &box_int, Label::kNear);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003400
3401 __ Integer32ToSmi(rax, rcx);
3402 __ ret(0);
3403
3404 __ bind(&box_int);
3405
3406 // Allocate a HeapNumber for the int and perform int-to-double
3407 // conversion.
3408 // The value is zero-extended since we loaded the value from memory
3409 // with movl.
3410 __ cvtqsi2sd(xmm0, rcx);
3411
3412 __ AllocateHeapNumber(rcx, rbx, &slow);
3413 // Set the value.
3414 __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
3415 __ movq(rax, rcx);
3416 __ ret(0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003417 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
3418 elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003419 // For the floating-point array type, we need to always allocate a
3420 // HeapNumber.
3421 __ AllocateHeapNumber(rcx, rbx, &slow);
3422 // Set the value.
3423 __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
3424 __ movq(rax, rcx);
3425 __ ret(0);
3426 } else {
3427 __ Integer32ToSmi(rax, rcx);
3428 __ ret(0);
3429 }
3430
3431 // Slow case: Jump to runtime.
3432 __ bind(&slow);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003433 Counters* counters = masm->isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003434 __ IncrementCounter(counters->keyed_load_external_array_slow(), 1);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003435
3436 // ----------- S t a t e -------------
3437 // -- rax : key
3438 // -- rdx : receiver
3439 // -- rsp[0] : return address
3440 // -----------------------------------
3441
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003442 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Slow();
3443 __ jmp(ic, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003444
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003445 // Miss case: Jump to runtime.
3446 __ bind(&miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003447
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003448 // ----------- S t a t e -------------
3449 // -- rax : key
3450 // -- rdx : receiver
3451 // -- rsp[0] : return address
3452 // -----------------------------------
3453 Handle<Code> miss_ic =
3454 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3455 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003456}
3457
3458
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003459void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3460 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003461 ElementsKind elements_kind) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003462 // ----------- S t a t e -------------
3463 // -- rax : value
3464 // -- rcx : key
3465 // -- rdx : receiver
3466 // -- rsp[0] : return address
3467 // -----------------------------------
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003468 Label slow, miss_force_generic;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003469
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003470 // This stub is meant to be tail-jumped to, the receiver must already
3471 // have been verified by the caller to not be a smi.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003472
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003473 // Check that the key is a smi or a heap number convertible to a smi.
3474 GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003475
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003476 // Check that the index is in range.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003477 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
danno@chromium.orgb6451162011-08-17 14:33:23 +00003478 __ SmiToInteger32(rdi, rcx); // Untag the index.
3479 __ cmpq(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003480 // Unsigned comparison catches both negative and too-large values.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003481 __ j(above_equal, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003482
3483 // Handle both smis and HeapNumbers in the fast path. Go to the
3484 // runtime for all other kinds of values.
3485 // rax: value
3486 // rcx: key (a smi)
3487 // rdx: receiver (a JSObject)
3488 // rbx: elements array
danno@chromium.orgb6451162011-08-17 14:33:23 +00003489 // rdi: untagged key
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003490 Label check_heap_number;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003491 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003492 // Float to pixel conversion is only implemented in the runtime for now.
3493 __ JumpIfNotSmi(rax, &slow);
3494 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003495 __ JumpIfNotSmi(rax, &check_heap_number, Label::kNear);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003496 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003497 // No more branches to slow case on this path. Key and receiver not needed.
3498 __ SmiToInteger32(rdx, rax);
3499 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
3500 // rbx: base pointer of external storage
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003501 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003502 case EXTERNAL_PIXEL_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003503 { // Clamp the value to [0..255].
3504 Label done;
3505 __ testl(rdx, Immediate(0xFFFFFF00));
3506 __ j(zero, &done, Label::kNear);
3507 __ setcc(negative, rdx); // 1 if negative, 0 if positive.
3508 __ decb(rdx); // 0 if negative, 255 if positive.
3509 __ bind(&done);
3510 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003511 __ movb(Operand(rbx, rdi, times_1, 0), rdx);
3512 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003513 case EXTERNAL_BYTE_ELEMENTS:
3514 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003515 __ movb(Operand(rbx, rdi, times_1, 0), rdx);
3516 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003517 case EXTERNAL_SHORT_ELEMENTS:
3518 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003519 __ movw(Operand(rbx, rdi, times_2, 0), rdx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003520 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003521 case EXTERNAL_INT_ELEMENTS:
3522 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
danno@chromium.orgb6451162011-08-17 14:33:23 +00003523 __ movl(Operand(rbx, rdi, times_4, 0), rdx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003524 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003525 case EXTERNAL_FLOAT_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003526 // Need to perform int-to-float conversion.
3527 __ cvtlsi2ss(xmm0, rdx);
danno@chromium.orgb6451162011-08-17 14:33:23 +00003528 __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003529 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003530 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003531 // Need to perform int-to-float conversion.
3532 __ cvtlsi2sd(xmm0, rdx);
danno@chromium.orgb6451162011-08-17 14:33:23 +00003533 __ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003534 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003535 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003536 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003537 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003538 case FAST_HOLEY_ELEMENTS:
3539 case FAST_HOLEY_SMI_ELEMENTS:
3540 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003541 case DICTIONARY_ELEMENTS:
3542 case NON_STRICT_ARGUMENTS_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003543 UNREACHABLE();
3544 break;
3545 }
3546 __ ret(0);
3547
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003548 // TODO(danno): handle heap number -> pixel array conversion
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003549 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003550 __ bind(&check_heap_number);
3551 // rax: value
3552 // rcx: key (a smi)
3553 // rdx: receiver (a JSObject)
3554 // rbx: elements array
danno@chromium.orgb6451162011-08-17 14:33:23 +00003555 // rdi: untagged key
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003556 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister);
3557 __ j(not_equal, &slow);
3558 // No more branches to slow case on this path.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003559
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003560 // The WebGL specification leaves the behavior of storing NaN and
3561 // +/-Infinity into integer arrays basically undefined. For more
3562 // reproducible behavior, convert these to zero.
3563 __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
3564 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
danno@chromium.orgb6451162011-08-17 14:33:23 +00003565 // rdi: untagged index
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003566 // rbx: base pointer of external storage
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003567 // top of FPU stack: value
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003568 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003569 __ cvtsd2ss(xmm0, xmm0);
danno@chromium.orgb6451162011-08-17 14:33:23 +00003570 __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003571 __ ret(0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003572 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00003573 __ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003574 __ ret(0);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003575 } else {
3576 // Perform float-to-int conversion with truncation (round-to-zero)
3577 // behavior.
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003578 // Fast path: use machine instruction to convert to int64. If that
3579 // fails (out-of-range), go into the runtime.
3580 __ cvttsd2siq(r8, xmm0);
3581 __ Set(kScratchRegister, V8_UINT64_C(0x8000000000000000));
3582 __ cmpq(r8, kScratchRegister);
3583 __ j(equal, &slow);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003584
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003585 // rdx: value (converted to an untagged integer)
3586 // rdi: untagged index
3587 // rbx: base pointer of external storage
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003588 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003589 case EXTERNAL_BYTE_ELEMENTS:
3590 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003591 __ movb(Operand(rbx, rdi, times_1, 0), r8);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003592 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003593 case EXTERNAL_SHORT_ELEMENTS:
3594 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003595 __ movw(Operand(rbx, rdi, times_2, 0), r8);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003596 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003597 case EXTERNAL_INT_ELEMENTS:
3598 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003599 __ movl(Operand(rbx, rdi, times_4, 0), r8);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003600 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003601 case EXTERNAL_PIXEL_ELEMENTS:
3602 case EXTERNAL_FLOAT_ELEMENTS:
3603 case EXTERNAL_DOUBLE_ELEMENTS:
3604 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003605 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003606 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003607 case FAST_HOLEY_ELEMENTS:
3608 case FAST_HOLEY_SMI_ELEMENTS:
3609 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003610 case DICTIONARY_ELEMENTS:
3611 case NON_STRICT_ARGUMENTS_ELEMENTS:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003612 UNREACHABLE();
3613 break;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003614 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003615 __ ret(0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003616 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003617 }
3618
3619 // Slow case: call runtime.
3620 __ bind(&slow);
3621
3622 // ----------- S t a t e -------------
3623 // -- rax : value
3624 // -- rcx : key
3625 // -- rdx : receiver
3626 // -- rsp[0] : return address
3627 // -----------------------------------
3628
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003629 Handle<Code> ic = masm->isolate()->builtins()->KeyedStoreIC_Slow();
3630 __ jmp(ic, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003631
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003632 // Miss case: call runtime.
3633 __ bind(&miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003634
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003635 // ----------- S t a t e -------------
3636 // -- rax : value
3637 // -- rcx : key
3638 // -- rdx : receiver
3639 // -- rsp[0] : return address
3640 // -----------------------------------
3641
3642 Handle<Code> miss_ic =
3643 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3644 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003645}
3646
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003647
3648void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
3649 // ----------- S t a t e -------------
3650 // -- rax : key
3651 // -- rdx : receiver
3652 // -- rsp[0] : return address
3653 // -----------------------------------
3654 Label miss_force_generic;
3655
3656 // This stub is meant to be tail-jumped to, the receiver must already
3657 // have been verified by the caller to not be a smi.
3658
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003659 // Check that the key is a smi or a heap number convertible to a smi.
3660 GenerateSmiKeyCheck(masm, rax, rcx, xmm0, xmm1, &miss_force_generic);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003661
3662 // Get the elements array.
3663 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
3664 __ AssertFastElements(rcx);
3665
3666 // Check that the key is within bounds.
3667 __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
3668 __ j(above_equal, &miss_force_generic);
3669
3670 // Load the result and make sure it's not the hole.
3671 SmiIndex index = masm->SmiToIndex(rbx, rax, kPointerSizeLog2);
3672 __ movq(rbx, FieldOperand(rcx,
3673 index.reg,
3674 index.scale,
3675 FixedArray::kHeaderSize));
3676 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
3677 __ j(equal, &miss_force_generic);
3678 __ movq(rax, rbx);
3679 __ ret(0);
3680
3681 __ bind(&miss_force_generic);
3682 Code* code = masm->isolate()->builtins()->builtin(
3683 Builtins::kKeyedLoadIC_MissForceGeneric);
3684 Handle<Code> ic(code);
3685 __ jmp(ic, RelocInfo::CODE_TARGET);
3686}
3687
3688
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003689void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
3690 MacroAssembler* masm) {
3691 // ----------- S t a t e -------------
3692 // -- rax : key
3693 // -- rdx : receiver
3694 // -- rsp[0] : return address
3695 // -----------------------------------
3696 Label miss_force_generic, slow_allocate_heapnumber;
3697
3698 // This stub is meant to be tail-jumped to, the receiver must already
3699 // have been verified by the caller to not be a smi.
3700
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003701 // Check that the key is a smi or a heap number convertible to a smi.
3702 GenerateSmiKeyCheck(masm, rax, rcx, xmm0, xmm1, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003703
3704 // Get the elements array.
3705 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
3706 __ AssertFastElements(rcx);
3707
3708 // Check that the key is within bounds.
3709 __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
3710 __ j(above_equal, &miss_force_generic);
3711
3712 // Check for the hole
3713 __ SmiToInteger32(kScratchRegister, rax);
3714 uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
3715 __ cmpl(FieldOperand(rcx, kScratchRegister, times_8, offset),
3716 Immediate(kHoleNanUpper32));
3717 __ j(equal, &miss_force_generic);
3718
3719 // Always allocate a heap number for the result.
3720 __ movsd(xmm0, FieldOperand(rcx, kScratchRegister, times_8,
3721 FixedDoubleArray::kHeaderSize));
3722 __ AllocateHeapNumber(rcx, rbx, &slow_allocate_heapnumber);
3723 // Set the value.
3724 __ movq(rax, rcx);
3725 __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
3726 __ ret(0);
3727
3728 __ bind(&slow_allocate_heapnumber);
3729 Handle<Code> slow_ic =
3730 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3731 __ jmp(slow_ic, RelocInfo::CODE_TARGET);
3732
3733 __ bind(&miss_force_generic);
3734 Handle<Code> miss_ic =
3735 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3736 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
3737}
3738
3739
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003740void KeyedStoreStubCompiler::GenerateStoreFastElement(
3741 MacroAssembler* masm,
3742 bool is_js_array,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003743 ElementsKind elements_kind,
3744 KeyedAccessGrowMode grow_mode) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003745 // ----------- S t a t e -------------
3746 // -- rax : value
3747 // -- rcx : key
3748 // -- rdx : receiver
3749 // -- rsp[0] : return address
3750 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003751 Label miss_force_generic, transition_elements_kind, finish_store, grow;
3752 Label check_capacity, slow;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003753
3754 // This stub is meant to be tail-jumped to, the receiver must already
3755 // have been verified by the caller to not be a smi.
3756
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003757 // Check that the key is a smi or a heap number convertible to a smi.
3758 GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003759
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003760 if (IsFastSmiElementsKind(elements_kind)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003761 __ JumpIfNotSmi(rax, &transition_elements_kind);
3762 }
3763
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003764 // Get the elements array and make sure it is a fast element array, not 'cow'.
3765 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003766 // Check that the key is within bounds.
3767 if (is_js_array) {
3768 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003769 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
3770 __ j(above_equal, &grow);
3771 } else {
3772 __ j(above_equal, &miss_force_generic);
3773 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003774 } else {
3775 __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
3776 __ j(above_equal, &miss_force_generic);
3777 }
3778
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003779 __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset),
3780 Heap::kFixedArrayMapRootIndex);
3781 __ j(not_equal, &miss_force_generic);
3782
3783 __ bind(&finish_store);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003784 if (IsFastSmiElementsKind(elements_kind)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003785 __ SmiToInteger32(rcx, rcx);
3786 __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize),
3787 rax);
3788 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003789 // Do the store and update the write barrier.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003790 ASSERT(IsFastObjectElementsKind(elements_kind));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003791 __ SmiToInteger32(rcx, rcx);
3792 __ lea(rcx,
3793 FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize));
3794 __ movq(Operand(rcx, 0), rax);
3795 // Make sure to preserve the value in register rax.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003796 __ movq(rbx, rax);
3797 __ RecordWrite(rdi, rcx, rbx, kDontSaveFPRegs);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003798 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003799
3800 // Done.
3801 __ ret(0);
3802
3803 // Handle store cache miss.
3804 __ bind(&miss_force_generic);
3805 Handle<Code> ic_force_generic =
3806 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3807 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003808
3809 __ bind(&transition_elements_kind);
3810 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
3811 __ jmp(ic_miss, RelocInfo::CODE_TARGET);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003812
3813 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
3814 // Grow the array by a single element if possible.
3815 __ bind(&grow);
3816
3817 // Make sure the array is only growing by a single element, anything else
3818 // must be handled by the runtime. Flags are already set by previous
3819 // compare.
3820 __ j(not_equal, &miss_force_generic);
3821
3822 // Check for the empty array, and preallocate a small backing store if
3823 // possible.
3824 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
3825 __ CompareRoot(rdi, Heap::kEmptyFixedArrayRootIndex);
3826 __ j(not_equal, &check_capacity);
3827
3828 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
3829 __ AllocateInNewSpace(size, rdi, rbx, r8, &slow, TAG_OBJECT);
3830
3831 // rax: value
3832 // rcx: key
3833 // rdx: receiver
3834 // rdi: elements
3835 // Make sure that the backing store can hold additional elements.
3836 __ Move(FieldOperand(rdi, JSObject::kMapOffset),
3837 masm->isolate()->factory()->fixed_array_map());
3838 __ Move(FieldOperand(rdi, FixedArray::kLengthOffset),
3839 Smi::FromInt(JSArray::kPreallocatedArrayElements));
3840 __ LoadRoot(rbx, Heap::kTheHoleValueRootIndex);
3841 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3842 __ movq(FieldOperand(rdi, FixedArray::SizeFor(i)), rbx);
3843 }
3844
3845 // Store the element at index zero.
3846 __ movq(FieldOperand(rdi, FixedArray::SizeFor(0)), rax);
3847
3848 // Install the new backing store in the JSArray.
3849 __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi);
3850 __ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx,
3851 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3852
3853 // Increment the length of the array.
3854 __ Move(FieldOperand(rdx, JSArray::kLengthOffset), Smi::FromInt(1));
3855 __ ret(0);
3856
3857 __ bind(&check_capacity);
3858 // Check for cow elements, in general they are not handled by this stub.
3859 __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset),
3860 Heap::kFixedCOWArrayMapRootIndex);
3861 __ j(equal, &miss_force_generic);
3862
3863 // rax: value
3864 // rcx: key
3865 // rdx: receiver
3866 // rdi: elements
3867 // Make sure that the backing store can hold additional elements.
3868 __ cmpq(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
3869 __ j(above_equal, &slow);
3870
3871 // Grow the array and finish the store.
3872 __ SmiAddConstant(FieldOperand(rdx, JSArray::kLengthOffset),
3873 Smi::FromInt(1));
3874 __ jmp(&finish_store);
3875
3876 __ bind(&slow);
3877 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
3878 __ jmp(ic_slow, RelocInfo::CODE_TARGET);
3879 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003880}
3881
3882
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003883void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3884 MacroAssembler* masm,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003885 bool is_js_array,
3886 KeyedAccessGrowMode grow_mode) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003887 // ----------- S t a t e -------------
3888 // -- rax : value
3889 // -- rcx : key
3890 // -- rdx : receiver
3891 // -- rsp[0] : return address
3892 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003893 Label miss_force_generic, transition_elements_kind, finish_store;
3894 Label grow, slow, check_capacity;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003895
3896 // This stub is meant to be tail-jumped to, the receiver must already
3897 // have been verified by the caller to not be a smi.
3898
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003899 // Check that the key is a smi or a heap number convertible to a smi.
3900 GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003901
3902 // Get the elements array.
3903 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
3904 __ AssertFastElements(rdi);
3905
3906 // Check that the key is within bounds.
3907 if (is_js_array) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003908 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
3909 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
3910 __ j(above_equal, &grow);
3911 } else {
3912 __ j(above_equal, &miss_force_generic);
3913 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003914 } else {
3915 __ SmiCompare(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003916 __ j(above_equal, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003917 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003918
3919 // Handle smi values specially
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003920 __ bind(&finish_store);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003921 __ SmiToInteger32(rcx, rcx);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003922 __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0,
3923 &transition_elements_kind);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003924 __ ret(0);
3925
3926 // Handle store cache miss, replacing the ic with the generic stub.
3927 __ bind(&miss_force_generic);
3928 Handle<Code> ic_force_generic =
3929 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3930 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003931
3932 __ bind(&transition_elements_kind);
3933 // Restore smi-tagging of rcx.
3934 __ Integer32ToSmi(rcx, rcx);
3935 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
3936 __ jmp(ic_miss, RelocInfo::CODE_TARGET);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003937
3938 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
3939 // Grow the array by a single element if possible.
3940 __ bind(&grow);
3941
3942 // Make sure the array is only growing by a single element, anything else
3943 // must be handled by the runtime. Flags are already set by previous
3944 // compare.
3945 __ j(not_equal, &miss_force_generic);
3946
3947 // Transition on values that can't be stored in a FixedDoubleArray.
3948 Label value_is_smi;
3949 __ JumpIfSmi(rax, &value_is_smi);
3950 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
3951 Heap::kHeapNumberMapRootIndex);
3952 __ j(not_equal, &transition_elements_kind);
3953 __ bind(&value_is_smi);
3954
3955 // Check for the empty array, and preallocate a small backing store if
3956 // possible.
3957 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
3958 __ CompareRoot(rdi, Heap::kEmptyFixedArrayRootIndex);
3959 __ j(not_equal, &check_capacity);
3960
3961 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
3962 __ AllocateInNewSpace(size, rdi, rbx, r8, &slow, TAG_OBJECT);
3963
3964 // rax: value
3965 // rcx: key
3966 // rdx: receiver
3967 // rdi: elements
3968 // Initialize the new FixedDoubleArray. Leave elements unitialized for
3969 // efficiency, they are guaranteed to be initialized before use.
3970 __ Move(FieldOperand(rdi, JSObject::kMapOffset),
3971 masm->isolate()->factory()->fixed_double_array_map());
3972 __ Move(FieldOperand(rdi, FixedDoubleArray::kLengthOffset),
3973 Smi::FromInt(JSArray::kPreallocatedArrayElements));
3974
3975 // Install the new backing store in the JSArray.
3976 __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi);
3977 __ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx,
3978 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3979
3980 // Increment the length of the array.
3981 __ Move(FieldOperand(rdx, JSArray::kLengthOffset), Smi::FromInt(1));
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003982 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003983 __ jmp(&finish_store);
3984
3985 __ bind(&check_capacity);
3986 // rax: value
3987 // rcx: key
3988 // rdx: receiver
3989 // rdi: elements
3990 // Make sure that the backing store can hold additional elements.
3991 __ cmpq(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset));
3992 __ j(above_equal, &slow);
3993
3994 // Grow the array and finish the store.
3995 __ SmiAddConstant(FieldOperand(rdx, JSArray::kLengthOffset),
3996 Smi::FromInt(1));
3997 __ jmp(&finish_store);
3998
3999 __ bind(&slow);
4000 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4001 __ jmp(ic_slow, RelocInfo::CODE_TARGET);
4002 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004003}
4004
4005
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004006#undef __
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004007
4008} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004009
4010#endif // V8_TARGET_ARCH_X64