blob: 44e64785858e91c06fd658ac049250e796883618 [file] [log] [blame]
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
28#include "v8.h"
29
30#include "ic-inl.h"
31#include "codegen-inl.h"
32#include "stub-cache.h"
33
kasperl@chromium.org71affb52009-05-26 05:44:31 +000034namespace v8 {
35namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036
ager@chromium.org65dad4b2009-04-23 08:48:43 +000037#define __ ACCESS_MASM(masm)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
39
40static void ProbeTable(MacroAssembler* masm,
41 Code::Flags flags,
42 StubCache::Table table,
43 Register name,
44 Register offset) {
45 ExternalReference key_offset(SCTableReference::keyReference(table));
46 ExternalReference value_offset(SCTableReference::valueReference(table));
47
48 Label miss;
49
50 // Save the offset on the stack.
51 __ push(offset);
52
53 // Check that the key in the entry matches the name.
54 __ mov(ip, Operand(key_offset));
55 __ ldr(ip, MemOperand(ip, offset, LSL, 1));
56 __ cmp(name, Operand(ip));
57 __ b(ne, &miss);
58
59 // Get the code entry from the cache.
60 __ mov(ip, Operand(value_offset));
61 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
62
63 // Check that the flags match what we're looking for.
64 __ ldr(offset, FieldMemOperand(offset, Code::kFlagsOffset));
kasperl@chromium.org71affb52009-05-26 05:44:31 +000065 __ and_(offset, offset, Operand(~Code::kFlagsNotUsedInLookup));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066 __ cmp(offset, Operand(flags));
67 __ b(ne, &miss);
68
69 // Restore offset and re-load code entry from cache.
70 __ pop(offset);
71 __ mov(ip, Operand(value_offset));
72 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
73
74 // Jump to the first instruction in the code stub.
75 __ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
76 __ Jump(offset);
77
78 // Miss: Restore offset and fall through.
79 __ bind(&miss);
80 __ pop(offset);
81}
82
83
84void StubCache::GenerateProbe(MacroAssembler* masm,
85 Code::Flags flags,
86 Register receiver,
87 Register name,
88 Register scratch) {
89 Label miss;
90
91 // Make sure that code is valid. The shifting code relies on the
92 // entry size being 8.
93 ASSERT(sizeof(Entry) == 8);
94
95 // Make sure the flags does not name a specific type.
96 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
97
98 // Make sure that there are no register conflicts.
99 ASSERT(!scratch.is(receiver));
100 ASSERT(!scratch.is(name));
101
102 // Check that the receiver isn't a smi.
103 __ tst(receiver, Operand(kSmiTagMask));
104 __ b(eq, &miss);
105
106 // Get the map of the receiver and compute the hash.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000107 __ ldr(scratch, FieldMemOperand(name, String::kLengthOffset));
108 __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109 __ add(scratch, scratch, Operand(ip));
110 __ eor(scratch, scratch, Operand(flags));
111 __ and_(scratch,
112 scratch,
113 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
114
115 // Probe the primary table.
116 ProbeTable(masm, flags, kPrimary, name, scratch);
117
118 // Primary miss: Compute hash for secondary probe.
119 __ sub(scratch, scratch, Operand(name));
120 __ add(scratch, scratch, Operand(flags));
121 __ and_(scratch,
122 scratch,
123 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
124
125 // Probe the secondary table.
126 ProbeTable(masm, flags, kSecondary, name, scratch);
127
128 // Cache miss: Fall-through and let caller handle the miss by
129 // entering the runtime system.
130 __ bind(&miss);
131}
132
133
134void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
135 int index,
136 Register prototype) {
137 // Load the global or builtins object from the current context.
138 __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
139 // Load the global context from the global or builtins object.
140 __ ldr(prototype,
141 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
142 // Load the function from the global context.
143 __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
144 // Load the initial map. The global functions all have initial maps.
145 __ ldr(prototype,
146 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
147 // Load the prototype from the initial map.
148 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
149}
150
151
ager@chromium.org7c537e22008-10-16 08:43:32 +0000152// Load a fast property out of a holder object (src). In-object properties
153// are loaded directly otherwise the property is loaded from the properties
154// fixed array.
155void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
156 Register dst, Register src,
157 JSObject* holder, int index) {
158 // Adjust for the number of properties stored in the holder.
159 index -= holder->map()->inobject_properties();
160 if (index < 0) {
161 // Get the property straight out of the holder.
162 int offset = holder->map()->instance_size() + (index * kPointerSize);
163 __ ldr(dst, FieldMemOperand(src, offset));
164 } else {
165 // Calculate the offset into the properties array.
166 int offset = index * kPointerSize + Array::kHeaderSize;
167 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
168 __ ldr(dst, FieldMemOperand(dst, offset));
169 }
170}
171
172
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000173void StubCompiler::GenerateLoadField(MacroAssembler* masm,
174 JSObject* object,
175 JSObject* holder,
176 Register receiver,
177 Register scratch1,
178 Register scratch2,
179 int index,
180 Label* miss_label) {
181 // Check that the receiver isn't a smi.
182 __ tst(receiver, Operand(kSmiTagMask));
183 __ b(eq, miss_label);
184
185 // Check that the maps haven't changed.
186 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000187 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000188 GenerateFastPropertyLoad(masm, r0, reg, holder, index);
189 __ Ret();
190}
191
192
193void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
194 JSObject* object,
195 JSObject* holder,
196 Register receiver,
197 Register scratch1,
198 Register scratch2,
199 Object* value,
200 Label* miss_label) {
201 // Check that the receiver isn't a smi.
202 __ tst(receiver, Operand(kSmiTagMask));
203 __ b(eq, miss_label);
204
205 // Check that the maps haven't changed.
206 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000207 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000208
209 // Return the constant value.
210 __ mov(r0, Operand(Handle<Object>(value)));
211 __ Ret();
212}
213
214
215void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
216 JSObject* object,
217 JSObject* holder,
218 Register receiver,
219 Register name,
220 Register scratch1,
221 Register scratch2,
222 AccessorInfo* callback,
223 Label* miss_label) {
224 // Check that the receiver isn't a smi.
225 __ tst(receiver, Operand(kSmiTagMask));
226 __ b(eq, miss_label);
227
228 // Check that the maps haven't changed.
229 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000230 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000231
232 // Push the arguments on the JS stack of the caller.
233 __ push(receiver); // receiver
234 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
235 __ push(ip);
236 __ push(name); // name
237 __ push(reg); // holder
238
239 // Do tail-call to the runtime system.
240 ExternalReference load_callback_property =
241 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
242 __ TailCallRuntime(load_callback_property, 4);
243}
244
245
246void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
247 JSObject* object,
248 JSObject* holder,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000249 Smi* lookup_hint,
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000250 Register receiver,
251 Register name,
252 Register scratch1,
253 Register scratch2,
254 Label* miss_label) {
255 // Check that the receiver isn't a smi.
256 __ tst(receiver, Operand(kSmiTagMask));
257 __ b(eq, miss_label);
258
259 // Check that the maps haven't changed.
260 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000261 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000262
263 // Push the arguments on the JS stack of the caller.
264 __ push(receiver); // receiver
265 __ push(reg); // holder
266 __ push(name); // name
ager@chromium.orge2902be2009-06-08 12:21:35 +0000267 __ mov(scratch1, Operand(lookup_hint));
268 __ push(scratch1);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000269
270 // Do tail-call to the runtime system.
271 ExternalReference load_ic_property =
272 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000273 __ TailCallRuntime(load_ic_property, 4);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000274}
275
276
277void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
278 Register receiver,
279 Register scratch,
280 Label* miss_label) {
281 // Check that the receiver isn't a smi.
282 __ tst(receiver, Operand(kSmiTagMask));
283 __ b(eq, miss_label);
284
285 // Check that the object is a JS array.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000286 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000287 __ b(ne, miss_label);
288
289 // Load length directly from the JS array.
290 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
291 __ Ret();
292}
293
294
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000295// Generate code to check if an object is a string. If the object is
296// a string, the map's instance type is left in the scratch1 register.
297static void GenerateStringCheck(MacroAssembler* masm,
298 Register receiver,
299 Register scratch1,
300 Register scratch2,
301 Label* smi,
302 Label* non_string_object) {
303 // Check that the receiver isn't a smi.
304 __ tst(receiver, Operand(kSmiTagMask));
305 __ b(eq, smi);
306
307 // Check that the object is a string.
308 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
309 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
310 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
311 // The cast is to resolve the overload for the argument of 0x0.
312 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
313 __ b(ne, non_string_object);
314}
315
316
ager@chromium.org32912102009-01-16 10:38:43 +0000317// Generate code to load the length from a string object and return the length.
318// If the receiver object is not a string or a wrapped string object the
319// execution continues at the miss label. The register containing the
320// receiver is potentially clobbered.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000321void StubCompiler::GenerateLoadStringLength2(MacroAssembler* masm,
322 Register receiver,
323 Register scratch1,
324 Register scratch2,
325 Label* miss) {
ager@chromium.org32912102009-01-16 10:38:43 +0000326 Label check_string, check_wrapper;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000327
ager@chromium.org32912102009-01-16 10:38:43 +0000328 __ bind(&check_string);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000329 // Check if the object is a string leaving the instance type in the
330 // scratch1 register.
331 GenerateStringCheck(masm, receiver, scratch1, scratch2,
332 miss, &check_wrapper);
333
334 // Load length directly from the string.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000335 __ and_(scratch1, scratch1, Operand(kStringSizeMask));
336 __ add(scratch1, scratch1, Operand(String::kHashShift));
337 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
338 __ mov(r0, Operand(r0, LSR, scratch1));
339 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
340 __ Ret();
341
342 // Check if the object is a JSValue wrapper.
343 __ bind(&check_wrapper);
344 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
345 __ b(ne, miss);
346
ager@chromium.org32912102009-01-16 10:38:43 +0000347 // Unwrap the value in place and check if the wrapped value is a string.
348 __ ldr(receiver, FieldMemOperand(receiver, JSValue::kValueOffset));
349 __ b(&check_string);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000350}
351
352
353// Generate StoreField code, value is passed in r0 register.
354// After executing generated code, the receiver_reg and name_reg
355// may be clobbered.
356void StubCompiler::GenerateStoreField(MacroAssembler* masm,
357 Builtins::Name storage_extend,
358 JSObject* object,
359 int index,
360 Map* transition,
361 Register receiver_reg,
362 Register name_reg,
363 Register scratch,
364 Label* miss_label) {
365 // r0 : value
366 Label exit;
367
368 // Check that the receiver isn't a smi.
369 __ tst(receiver_reg, Operand(kSmiTagMask));
370 __ b(eq, miss_label);
371
372 // Check that the map of the receiver hasn't changed.
373 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
374 __ cmp(scratch, Operand(Handle<Map>(object->map())));
375 __ b(ne, miss_label);
376
377 // Perform global security token check if needed.
378 if (object->IsJSGlobalProxy()) {
379 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
380 }
381
382 // Stub never generated for non-global objects that require access
383 // checks.
384 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
385
386 // Perform map transition for the receiver if necessary.
387 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
388 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000389 // We jump to a runtime call that extends the properties array.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000390 __ mov(r2, Operand(Handle<Map>(transition)));
391 // Please note, if we implement keyed store for arm we need
392 // to call the Builtins::KeyedStoreIC_ExtendStorage.
393 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage));
394 __ Jump(ic, RelocInfo::CODE_TARGET);
395 return;
396 }
397
398 if (transition != NULL) {
399 // Update the map of the object; no write barrier updating is
400 // needed because the map is never in new space.
401 __ mov(ip, Operand(Handle<Map>(transition)));
402 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
403 }
404
405 // Adjust for the number of properties stored in the object. Even in the
406 // face of a transition we can use the old map here because the size of the
407 // object and the number of in-object properties is not going to change.
408 index -= object->map()->inobject_properties();
409
410 if (index < 0) {
411 // Set the property straight into the object.
412 int offset = object->map()->instance_size() + (index * kPointerSize);
413 __ str(r0, FieldMemOperand(receiver_reg, offset));
414
415 // Skip updating write barrier if storing a smi.
416 __ tst(r0, Operand(kSmiTagMask));
417 __ b(eq, &exit);
418
419 // Update the write barrier for the array address.
420 // Pass the value being stored in the now unused name_reg.
421 __ mov(name_reg, Operand(offset));
422 __ RecordWrite(receiver_reg, name_reg, scratch);
423 } else {
424 // Write to the properties array.
425 int offset = index * kPointerSize + Array::kHeaderSize;
426 // Get the properties array
427 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
428 __ str(r0, FieldMemOperand(scratch, offset));
429
430 // Skip updating write barrier if storing a smi.
431 __ tst(r0, Operand(kSmiTagMask));
432 __ b(eq, &exit);
433
434 // Update the write barrier for the array address.
435 // Ok to clobber receiver_reg and name_reg, since we return.
436 __ mov(name_reg, Operand(offset));
437 __ RecordWrite(scratch, name_reg, receiver_reg);
438 }
439
440 // Return the value (register r0).
441 __ bind(&exit);
442 __ Ret();
443}
444
445
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000446void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
447 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
448 Code* code = NULL;
449 if (kind == Code::LOAD_IC) {
450 code = Builtins::builtin(Builtins::LoadIC_Miss);
451 } else {
452 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
453 }
454
455 Handle<Code> ic(code);
456 __ Jump(ic, RelocInfo::CODE_TARGET);
457}
458
459
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000460#undef __
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000461#define __ ACCESS_MASM(masm())
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000462
463
464Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000465 // ----------- S t a t e -------------
466 // -- r1: function
467 // -- lr: return address
468 // -----------------------------------
469
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000470 // Enter an internal frame.
471 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000472
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000473 // Preserve the function.
474 __ push(r1);
475
476 // Push the function on the stack as the argument to the runtime function.
477 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000478 __ CallRuntime(Runtime::kLazyCompile, 1);
479
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000480 // Calculate the entry point.
481 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000482
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000483 // Restore saved function.
484 __ pop(r1);
485
486 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000487 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000488
489 // Do a tail-call of the compiled function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000490 __ Jump(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000492 return GetCodeWithFlags(flags, "LazyCompileStub");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000493}
494
495
496Object* CallStubCompiler::CompileCallField(Object* object,
497 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000498 int index,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000499 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000500 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501 // -- lr: return address
502 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000503 Label miss;
504
mads.s.ager31e71382008-08-13 09:32:07 +0000505 const int argc = arguments().immediate();
506
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000507 // Get the receiver of the function from the stack into r0.
508 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509 // Check that the receiver isn't a smi.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000510 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000511 __ b(eq, &miss);
512
513 // Do the right check and compute the holder register.
514 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000515 masm()->CheckMaps(JSObject::cast(object), r0, holder, r3, r2, &miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000516 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000517
518 // Check that the function really is a function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000519 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000520 __ b(eq, &miss);
521 // Get the map.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000522 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000523 __ b(ne, &miss);
524
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000525 // Patch the receiver on the stack with the global proxy if
526 // necessary.
527 if (object->IsGlobalObject()) {
528 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
529 __ str(r3, MemOperand(sp, argc * kPointerSize));
530 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000532 // Invoke the function.
533 __ InvokeFunction(r1, arguments(), JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000534
535 // Handle call cache miss.
536 __ bind(&miss);
537 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000538 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000539
540 // Return the generated code.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000541 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542}
543
544
545Object* CallStubCompiler::CompileCallConstant(Object* object,
546 JSObject* holder,
547 JSFunction* function,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000548 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550 // -- lr: return address
551 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000552 Label miss;
553
mads.s.ager31e71382008-08-13 09:32:07 +0000554 // Get the receiver from the stack
555 const int argc = arguments().immediate();
556 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
557
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000558 // Check that the receiver isn't a smi.
559 if (check != NUMBER_CHECK) {
560 __ tst(r1, Operand(kSmiTagMask));
561 __ b(eq, &miss);
562 }
563
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000564 // Make sure that it's okay not to patch the on stack receiver
565 // unless we're doing a receiver map check.
566 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
567
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568 switch (check) {
569 case RECEIVER_MAP_CHECK:
570 // Check that the maps haven't changed.
571 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000572
573 // Patch the receiver on the stack with the global proxy if
574 // necessary.
575 if (object->IsGlobalObject()) {
576 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
577 __ str(r3, MemOperand(sp, argc * kPointerSize));
578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000579 break;
580
581 case STRING_CHECK:
582 // Check that the object is a two-byte string or a symbol.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000583 __ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000584 __ b(hs, &miss);
585 // Check that the maps starting from the prototype haven't changed.
586 GenerateLoadGlobalFunctionPrototype(masm(),
587 Context::STRING_FUNCTION_INDEX,
588 r2);
589 __ CheckMaps(JSObject::cast(object->GetPrototype()),
590 r2, holder, r3, r1, &miss);
591 break;
592
593 case NUMBER_CHECK: {
594 Label fast;
595 // Check that the object is a smi or a heap number.
596 __ tst(r1, Operand(kSmiTagMask));
597 __ b(eq, &fast);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000598 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599 __ b(ne, &miss);
600 __ bind(&fast);
601 // Check that the maps starting from the prototype haven't changed.
602 GenerateLoadGlobalFunctionPrototype(masm(),
603 Context::NUMBER_FUNCTION_INDEX,
604 r2);
605 __ CheckMaps(JSObject::cast(object->GetPrototype()),
606 r2, holder, r3, r1, &miss);
607 break;
608 }
609
610 case BOOLEAN_CHECK: {
611 Label fast;
612 // Check that the object is a boolean.
613 __ cmp(r1, Operand(Factory::true_value()));
614 __ b(eq, &fast);
615 __ cmp(r1, Operand(Factory::false_value()));
616 __ b(ne, &miss);
617 __ bind(&fast);
618 // Check that the maps starting from the prototype haven't changed.
619 GenerateLoadGlobalFunctionPrototype(masm(),
620 Context::BOOLEAN_FUNCTION_INDEX,
621 r2);
622 __ CheckMaps(JSObject::cast(object->GetPrototype()),
623 r2, holder, r3, r1, &miss);
624 break;
625 }
626
627 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
628 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
629 // Make sure object->elements()->map() != Heap::hash_table_map()
630 // Get the elements array of the object.
631 __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
632 // Check that the object is in fast mode (not dictionary).
633 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
634 __ cmp(r2, Operand(Factory::hash_table_map()));
635 __ b(eq, &miss);
636 break;
637
638 default:
639 UNREACHABLE();
640 }
641
642 // Get the function and setup the context.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000643 __ mov(r1, Operand(Handle<JSFunction>(function)));
644 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000645
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000646 // Jump to the cached code (tail call).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000647 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648 Handle<Code> code(function->code());
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000649 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +0000650 __ InvokeCode(code, expected, arguments(),
651 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000652
653 // Handle call cache miss.
654 __ bind(&miss);
655 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000656 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657
658 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000659 String* function_name = NULL;
660 if (function->shared()->name()->IsString()) {
661 function_name = String::cast(function->shared()->name());
662 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000663 return GetCode(CONSTANT_FUNCTION, function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000664}
665
666
667Object* CallStubCompiler::CompileCallInterceptor(Object* object,
668 JSObject* holder,
669 String* name) {
670 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000671 // -- lr: return address
672 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000673 Label miss;
674
675 // TODO(1224669): Implement.
676
677 // Handle call cache miss.
678 __ bind(&miss);
679 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000680 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000681
682 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000683 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000684}
685
686
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000687Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
688 JSGlobalPropertyCell* cell,
689 JSFunction* function,
690 String* name) {
691 // ----------- S t a t e -------------
692 // -- lr: return address
693 // -----------------------------------
694 Label miss;
695
696 __ IncrementCounter(&Counters::call_global_inline, 1, r1, r3);
697
698 // Get the number of arguments.
699 const int argc = arguments().immediate();
700
701 // Check that the map of the global has not changed.
702 __ ldr(r2, MemOperand(sp, argc * kPointerSize));
703 __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
704 __ cmp(r3, Operand(Handle<Map>(object->map())));
705 __ b(ne, &miss);
706
707 // Get the value from the cell.
708 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
709 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
710
711 // Check that the cell contains the same function.
712 __ cmp(r1, Operand(Handle<JSFunction>(function)));
713 __ b(ne, &miss);
714
715 // Patch the receiver on the stack with the global proxy if
716 // necessary.
717 __ ldr(r3, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
718 __ str(r3, MemOperand(sp, argc * kPointerSize));
719
720 // Setup the context (function already in r1).
721 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
722
723 // Jump to the cached code (tail call).
724 ASSERT(function->is_compiled());
725 Handle<Code> code(function->code());
726 ParameterCount expected(function->shared()->formal_parameter_count());
727 __ InvokeCode(code, expected, arguments(),
728 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
729
730 // Handle call cache miss.
731 __ bind(&miss);
732 __ DecrementCounter(&Counters::call_global_inline, 1, r1, r3);
733 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
734 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
735 __ Jump(ic, RelocInfo::CODE_TARGET);
736
737 // Return the generated code.
738 return GetCode(NORMAL, name);
739}
740
741
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000742Object* StoreStubCompiler::CompileStoreField(JSObject* object,
743 int index,
744 Map* transition,
745 String* name) {
746 // ----------- S t a t e -------------
747 // -- r0 : value
748 // -- r2 : name
749 // -- lr : return address
750 // -- [sp] : receiver
751 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000752 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000753
754 // Get the receiver from the stack.
755 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
756
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000757 // name register might be clobbered.
758 GenerateStoreField(masm(),
759 Builtins::StoreIC_ExtendStorage,
760 object,
761 index,
762 transition,
763 r3, r2, r1,
764 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000765 __ bind(&miss);
766 __ mov(r2, Operand(Handle<String>(name))); // restore name
767 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000768 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769
770 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000771 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000772}
773
774
775Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
776 AccessorInfo* callback,
777 String* name) {
778 // ----------- S t a t e -------------
779 // -- r0 : value
780 // -- r2 : name
781 // -- lr : return address
782 // -- [sp] : receiver
783 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000784 Label miss;
785
786 // Get the object from the stack.
787 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
788
789 // Check that the object isn't a smi.
790 __ tst(r3, Operand(kSmiTagMask));
791 __ b(eq, &miss);
792
793 // Check that the map of the object hasn't changed.
794 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
795 __ cmp(r1, Operand(Handle<Map>(object->map())));
796 __ b(ne, &miss);
797
798 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000799 if (object->IsJSGlobalProxy()) {
800 __ CheckAccessGlobalProxy(r3, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000801 }
802
803 // Stub never generated for non-global objects that require access
804 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000805 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000806
807 __ ldr(ip, MemOperand(sp)); // receiver
808 __ push(ip);
809 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
810 __ push(ip);
811 __ push(r2); // name
812 __ push(r0); // value
813
mads.s.ager31e71382008-08-13 09:32:07 +0000814 // Do tail-call to the runtime system.
815 ExternalReference store_callback_property =
816 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
817 __ TailCallRuntime(store_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000818
819 // Handle store cache miss.
820 __ bind(&miss);
821 __ mov(r2, Operand(Handle<String>(name))); // restore name
822 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000823 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000824
825 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000826 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827}
828
829
830Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
831 String* name) {
832 // ----------- S t a t e -------------
833 // -- r0 : value
834 // -- r2 : name
835 // -- lr : return address
836 // -- [sp] : receiver
837 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000838 Label miss;
839
840 // Get the object from the stack.
841 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
842
843 // Check that the object isn't a smi.
844 __ tst(r3, Operand(kSmiTagMask));
845 __ b(eq, &miss);
846
847 // Check that the map of the object hasn't changed.
848 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
849 __ cmp(r1, Operand(Handle<Map>(receiver->map())));
850 __ b(ne, &miss);
851
852 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000853 if (receiver->IsJSGlobalProxy()) {
854 __ CheckAccessGlobalProxy(r3, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000855 }
856
857 // Stub never generated for non-global objects that require access
858 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000859 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000860
861 __ ldr(ip, MemOperand(sp)); // receiver
862 __ push(ip);
863 __ push(r2); // name
864 __ push(r0); // value
865
mads.s.ager31e71382008-08-13 09:32:07 +0000866 // Do tail-call to the runtime system.
867 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000869 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000870
871 // Handle store cache miss.
872 __ bind(&miss);
873 __ mov(r2, Operand(Handle<String>(name))); // restore name
874 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000875 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000876
877 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000878 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000879}
880
881
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000882Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
883 JSGlobalPropertyCell* cell,
884 String* name) {
885 // ----------- S t a t e -------------
886 // -- r0 : value
887 // -- r2 : name
888 // -- lr : return address
889 // -- [sp] : receiver
890 // -----------------------------------
891 Label miss;
892
893 __ IncrementCounter(&Counters::named_store_global_inline, 1, r1, r3);
894
895 // Check that the map of the global has not changed.
896 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
897 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
898 __ cmp(r3, Operand(Handle<Map>(object->map())));
899 __ b(ne, &miss);
900
901 // Store the value in the cell.
902 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
903 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
904 __ mov(r1, Operand(JSGlobalPropertyCell::kValueOffset));
905 __ RecordWrite(r2, r1, r3);
906
907 __ Ret();
908
909 // Handle store cache miss.
910 __ bind(&miss);
911 __ DecrementCounter(&Counters::named_store_global_inline, 1, r1, r3);
912 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r1, r3);
913 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
914 __ Jump(ic, RelocInfo::CODE_TARGET);
915
916 // Return the generated code.
917 return GetCode(NORMAL, name);
918}
919
920
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000921Object* LoadStubCompiler::CompileLoadField(JSObject* object,
922 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000923 int index,
924 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926 // -- r2 : name
927 // -- lr : return address
928 // -- [sp] : receiver
929 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000930 Label miss;
931
mads.s.ager31e71382008-08-13 09:32:07 +0000932 __ ldr(r0, MemOperand(sp, 0));
933
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000934 GenerateLoadField(masm(), object, holder, r0, r3, r1, index, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000935 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000936 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000937
938 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000939 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000940}
941
942
943Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
944 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000945 AccessorInfo* callback,
946 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000947 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000948 // -- r2 : name
949 // -- lr : return address
950 // -- [sp] : receiver
951 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000952 Label miss;
953
mads.s.ager31e71382008-08-13 09:32:07 +0000954 __ ldr(r0, MemOperand(sp, 0));
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000955 GenerateLoadCallback(masm(), object, holder, r0, r2, r3, r1, callback, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000956 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000957 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000958
959 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000960 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000961}
962
963
964Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
965 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000966 Object* value,
967 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000968 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000969 // -- r2 : name
970 // -- lr : return address
971 // -- [sp] : receiver
972 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000973 Label miss;
974
mads.s.ager31e71382008-08-13 09:32:07 +0000975 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000976
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000977 GenerateLoadConstant(masm(), object, holder, r0, r3, r1, value, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000978 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000979 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000980
981 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000982 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000983}
984
985
986Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
987 JSObject* holder,
988 String* name) {
989 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000990 // -- r2 : name
991 // -- lr : return address
992 // -- [sp] : receiver
993 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000994 Label miss;
995
mads.s.ager31e71382008-08-13 09:32:07 +0000996 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997
ager@chromium.orge2902be2009-06-08 12:21:35 +0000998 GenerateLoadInterceptor(masm(),
999 object,
1000 holder,
1001 holder->InterceptorPropertyLookupHint(name),
1002 r0,
1003 r2,
1004 r3,
1005 r1,
1006 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001008 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009
1010 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001011 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012}
1013
1014
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001015Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
1016 JSGlobalPropertyCell* cell,
1017 String* name,
1018 bool is_dont_delete) {
1019 // ----------- S t a t e -------------
1020 // -- r2 : name
1021 // -- lr : return address
1022 // -- [sp] : receiver
1023 // -----------------------------------
1024 Label miss;
1025
1026 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
1027
1028 // Check that the map of the global has not changed.
1029 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
1030 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1031 __ cmp(r3, Operand(Handle<Map>(object->map())));
1032 __ b(ne, &miss);
1033
1034 // Get the value from the cell.
1035 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1036 __ ldr(r0, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1037
1038 // Check for deleted property if property can actually be deleted.
1039 if (!is_dont_delete) {
1040 __ cmp(r0, Operand(Factory::the_hole_value()));
1041 __ b(eq, &miss);
1042 }
1043
1044 __ Ret();
1045
1046 __ bind(&miss);
1047 __ DecrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
1048 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1049 GenerateLoadMiss(masm(), Code::LOAD_IC);
1050
1051 // Return the generated code.
1052 return GetCode(NORMAL, name);
1053}
1054
1055
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001056// TODO(1224671): IC stubs for keyed loads have not been implemented
1057// for ARM.
1058Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1059 JSObject* receiver,
1060 JSObject* holder,
1061 int index) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001062 // ----------- S t a t e -------------
1063 // -- lr : return address
1064 // -- sp[0] : key
1065 // -- sp[4] : receiver
1066 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001067 Label miss;
1068
1069 __ ldr(r2, MemOperand(sp, 0));
1070 __ ldr(r0, MemOperand(sp, kPointerSize));
1071
1072 __ cmp(r2, Operand(Handle<String>(name)));
1073 __ b(ne, &miss);
1074
1075 GenerateLoadField(masm(), receiver, holder, r0, r3, r1, index, &miss);
1076 __ bind(&miss);
1077 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1078
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001079 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080}
1081
1082
1083Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1084 JSObject* receiver,
1085 JSObject* holder,
1086 AccessorInfo* callback) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001087 // ----------- S t a t e -------------
1088 // -- lr : return address
1089 // -- sp[0] : key
1090 // -- sp[4] : receiver
1091 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001092 Label miss;
1093
1094 __ ldr(r2, MemOperand(sp, 0));
1095 __ ldr(r0, MemOperand(sp, kPointerSize));
1096
1097 __ cmp(r2, Operand(Handle<String>(name)));
1098 __ b(ne, &miss);
1099
1100 GenerateLoadCallback(masm(), receiver, holder, r0, r2, r3,
1101 r1, callback, &miss);
1102 __ bind(&miss);
1103 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1104
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001105 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106}
1107
1108
1109Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1110 JSObject* receiver,
1111 JSObject* holder,
1112 Object* value) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001113 // ----------- S t a t e -------------
1114 // -- lr : return address
1115 // -- sp[0] : key
1116 // -- sp[4] : receiver
1117 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001118 Label miss;
1119
1120 // Check the key is the cached one
1121 __ ldr(r2, MemOperand(sp, 0));
1122 __ ldr(r0, MemOperand(sp, kPointerSize));
1123
1124 __ cmp(r2, Operand(Handle<String>(name)));
1125 __ b(ne, &miss);
1126
1127 GenerateLoadConstant(masm(), receiver, holder, r0, r3, r1, value, &miss);
1128 __ bind(&miss);
1129 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1130
1131 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001132 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001133}
1134
1135
1136Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1137 JSObject* holder,
1138 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001139 // ----------- S t a t e -------------
1140 // -- lr : return address
1141 // -- sp[0] : key
1142 // -- sp[4] : receiver
1143 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001144 Label miss;
1145
1146 // Check the key is the cached one
1147 __ ldr(r2, MemOperand(sp, 0));
1148 __ ldr(r0, MemOperand(sp, kPointerSize));
1149
1150 __ cmp(r2, Operand(Handle<String>(name)));
1151 __ b(ne, &miss);
1152
ager@chromium.orge2902be2009-06-08 12:21:35 +00001153 GenerateLoadInterceptor(masm(),
1154 receiver,
1155 holder,
1156 Smi::FromInt(JSObject::kLookupInHolder),
1157 r0,
1158 r2,
1159 r3,
1160 r1,
1161 &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001162 __ bind(&miss);
1163 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1164
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001165 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001166}
1167
1168
1169Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001170 // ----------- S t a t e -------------
1171 // -- lr : return address
1172 // -- sp[0] : key
1173 // -- sp[4] : receiver
1174 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001175 Label miss;
1176
1177 // Check the key is the cached one
1178 __ ldr(r2, MemOperand(sp, 0));
1179 __ ldr(r0, MemOperand(sp, kPointerSize));
1180
1181 __ cmp(r2, Operand(Handle<String>(name)));
1182 __ b(ne, &miss);
1183
1184 GenerateLoadArrayLength(masm(), r0, r3, &miss);
1185 __ bind(&miss);
1186 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1187
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001188 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001189}
1190
1191
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001192Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001193 // ----------- S t a t e -------------
1194 // -- lr : return address
1195 // -- sp[0] : key
1196 // -- sp[4] : receiver
1197 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001198 Label miss;
1199 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1200
1201 __ ldr(r2, MemOperand(sp));
1202 __ ldr(r0, MemOperand(sp, kPointerSize)); // receiver
1203
1204 __ cmp(r2, Operand(Handle<String>(name)));
1205 __ b(ne, &miss);
1206
1207 GenerateLoadStringLength2(masm(), r0, r1, r3, &miss);
1208 __ bind(&miss);
1209 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1210
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001211 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1212
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001213 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214}
1215
1216
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001217// TODO(1224671): implement the fast case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001219 // ----------- S t a t e -------------
1220 // -- lr : return address
1221 // -- sp[0] : key
1222 // -- sp[4] : receiver
1223 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001224 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1225
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001226 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001227}
1228
1229
1230Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1231 int index,
1232 Map* transition,
1233 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001234 // ----------- S t a t e -------------
1235 // -- r0 : value
1236 // -- r2 : name
1237 // -- lr : return address
1238 // -- [sp] : receiver
1239 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001240 Label miss;
1241
1242 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1243
1244 // Check that the name has not changed.
1245 __ cmp(r2, Operand(Handle<String>(name)));
1246 __ b(ne, &miss);
1247
1248 // Load receiver from the stack.
1249 __ ldr(r3, MemOperand(sp));
1250 // r1 is used as scratch register, r3 and r2 might be clobbered.
1251 GenerateStoreField(masm(),
1252 Builtins::StoreIC_ExtendStorage,
1253 object,
1254 index,
1255 transition,
1256 r3, r2, r1,
1257 &miss);
1258 __ bind(&miss);
1259
1260 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1261 __ mov(r2, Operand(Handle<String>(name))); // restore name register.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001262 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
1263 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001265 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001266 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001267}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268
1269
1270#undef __
1271
1272} } // namespace v8::internal