blob: e3e5502d6b8fae4e76c9ae75c2113345b6015bd0 [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,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000088 Register scratch,
89 Register extra) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000090 Label miss;
91
92 // Make sure that code is valid. The shifting code relies on the
93 // entry size being 8.
94 ASSERT(sizeof(Entry) == 8);
95
96 // Make sure the flags does not name a specific type.
97 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
98
99 // Make sure that there are no register conflicts.
100 ASSERT(!scratch.is(receiver));
101 ASSERT(!scratch.is(name));
102
103 // Check that the receiver isn't a smi.
104 __ tst(receiver, Operand(kSmiTagMask));
105 __ b(eq, &miss);
106
107 // Get the map of the receiver and compute the hash.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000108 __ ldr(scratch, FieldMemOperand(name, String::kLengthOffset));
109 __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110 __ add(scratch, scratch, Operand(ip));
111 __ eor(scratch, scratch, Operand(flags));
112 __ and_(scratch,
113 scratch,
114 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
115
116 // Probe the primary table.
117 ProbeTable(masm, flags, kPrimary, name, scratch);
118
119 // Primary miss: Compute hash for secondary probe.
120 __ sub(scratch, scratch, Operand(name));
121 __ add(scratch, scratch, Operand(flags));
122 __ and_(scratch,
123 scratch,
124 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
125
126 // Probe the secondary table.
127 ProbeTable(masm, flags, kSecondary, name, scratch);
128
129 // Cache miss: Fall-through and let caller handle the miss by
130 // entering the runtime system.
131 __ bind(&miss);
132}
133
134
135void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
136 int index,
137 Register prototype) {
138 // Load the global or builtins object from the current context.
139 __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
140 // Load the global context from the global or builtins object.
141 __ ldr(prototype,
142 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
143 // Load the function from the global context.
144 __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
145 // Load the initial map. The global functions all have initial maps.
146 __ ldr(prototype,
147 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
148 // Load the prototype from the initial map.
149 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
150}
151
152
ager@chromium.org7c537e22008-10-16 08:43:32 +0000153// Load a fast property out of a holder object (src). In-object properties
154// are loaded directly otherwise the property is loaded from the properties
155// fixed array.
156void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
157 Register dst, Register src,
158 JSObject* holder, int index) {
159 // Adjust for the number of properties stored in the holder.
160 index -= holder->map()->inobject_properties();
161 if (index < 0) {
162 // Get the property straight out of the holder.
163 int offset = holder->map()->instance_size() + (index * kPointerSize);
164 __ ldr(dst, FieldMemOperand(src, offset));
165 } else {
166 // Calculate the offset into the properties array.
167 int offset = index * kPointerSize + Array::kHeaderSize;
168 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
169 __ ldr(dst, FieldMemOperand(dst, offset));
170 }
171}
172
173
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000174void StubCompiler::GenerateLoadField(MacroAssembler* masm,
175 JSObject* object,
176 JSObject* holder,
177 Register receiver,
178 Register scratch1,
179 Register scratch2,
180 int index,
181 Label* miss_label) {
182 // Check that the receiver isn't a smi.
183 __ tst(receiver, Operand(kSmiTagMask));
184 __ b(eq, miss_label);
185
186 // Check that the maps haven't changed.
187 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000188 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000189 GenerateFastPropertyLoad(masm, r0, reg, holder, index);
190 __ Ret();
191}
192
193
194void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
195 JSObject* object,
196 JSObject* holder,
197 Register receiver,
198 Register scratch1,
199 Register scratch2,
200 Object* value,
201 Label* miss_label) {
202 // Check that the receiver isn't a smi.
203 __ tst(receiver, Operand(kSmiTagMask));
204 __ b(eq, miss_label);
205
206 // Check that the maps haven't changed.
207 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000208 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000209
210 // Return the constant value.
211 __ mov(r0, Operand(Handle<Object>(value)));
212 __ Ret();
213}
214
215
216void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
217 JSObject* object,
218 JSObject* holder,
219 Register receiver,
220 Register name,
221 Register scratch1,
222 Register scratch2,
223 AccessorInfo* callback,
224 Label* miss_label) {
225 // Check that the receiver isn't a smi.
226 __ tst(receiver, Operand(kSmiTagMask));
227 __ b(eq, miss_label);
228
229 // Check that the maps haven't changed.
230 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000231 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000232
233 // Push the arguments on the JS stack of the caller.
234 __ push(receiver); // receiver
235 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
236 __ push(ip);
237 __ push(name); // name
238 __ push(reg); // holder
239
240 // Do tail-call to the runtime system.
241 ExternalReference load_callback_property =
242 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
243 __ TailCallRuntime(load_callback_property, 4);
244}
245
246
247void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
248 JSObject* object,
249 JSObject* holder,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000250 Smi* lookup_hint,
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000251 Register receiver,
252 Register name,
253 Register scratch1,
254 Register scratch2,
255 Label* miss_label) {
256 // Check that the receiver isn't a smi.
257 __ tst(receiver, Operand(kSmiTagMask));
258 __ b(eq, miss_label);
259
260 // Check that the maps haven't changed.
261 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000262 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000263
264 // Push the arguments on the JS stack of the caller.
265 __ push(receiver); // receiver
266 __ push(reg); // holder
267 __ push(name); // name
ager@chromium.orge2902be2009-06-08 12:21:35 +0000268 __ mov(scratch1, Operand(lookup_hint));
269 __ push(scratch1);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000270
271 // Do tail-call to the runtime system.
272 ExternalReference load_ic_property =
273 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000274 __ TailCallRuntime(load_ic_property, 4);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000275}
276
277
278void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
279 Register receiver,
280 Register scratch,
281 Label* miss_label) {
282 // Check that the receiver isn't a smi.
283 __ tst(receiver, Operand(kSmiTagMask));
284 __ b(eq, miss_label);
285
286 // Check that the object is a JS array.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000287 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000288 __ b(ne, miss_label);
289
290 // Load length directly from the JS array.
291 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
292 __ Ret();
293}
294
295
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000296// Generate code to check if an object is a string. If the object is
297// a string, the map's instance type is left in the scratch1 register.
298static void GenerateStringCheck(MacroAssembler* masm,
299 Register receiver,
300 Register scratch1,
301 Register scratch2,
302 Label* smi,
303 Label* non_string_object) {
304 // Check that the receiver isn't a smi.
305 __ tst(receiver, Operand(kSmiTagMask));
306 __ b(eq, smi);
307
308 // Check that the object is a string.
309 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
310 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
311 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
312 // The cast is to resolve the overload for the argument of 0x0.
313 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
314 __ b(ne, non_string_object);
315}
316
317
ager@chromium.org32912102009-01-16 10:38:43 +0000318// Generate code to load the length from a string object and return the length.
319// If the receiver object is not a string or a wrapped string object the
320// execution continues at the miss label. The register containing the
321// receiver is potentially clobbered.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000322void StubCompiler::GenerateLoadStringLength2(MacroAssembler* masm,
323 Register receiver,
324 Register scratch1,
325 Register scratch2,
326 Label* miss) {
ager@chromium.org32912102009-01-16 10:38:43 +0000327 Label check_string, check_wrapper;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000328
ager@chromium.org32912102009-01-16 10:38:43 +0000329 __ bind(&check_string);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000330 // Check if the object is a string leaving the instance type in the
331 // scratch1 register.
332 GenerateStringCheck(masm, receiver, scratch1, scratch2,
333 miss, &check_wrapper);
334
335 // Load length directly from the string.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000336 __ and_(scratch1, scratch1, Operand(kStringSizeMask));
337 __ add(scratch1, scratch1, Operand(String::kHashShift));
338 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
339 __ mov(r0, Operand(r0, LSR, scratch1));
340 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
341 __ Ret();
342
343 // Check if the object is a JSValue wrapper.
344 __ bind(&check_wrapper);
345 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
346 __ b(ne, miss);
347
ager@chromium.org32912102009-01-16 10:38:43 +0000348 // Unwrap the value in place and check if the wrapped value is a string.
349 __ ldr(receiver, FieldMemOperand(receiver, JSValue::kValueOffset));
350 __ b(&check_string);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000351}
352
353
354// Generate StoreField code, value is passed in r0 register.
355// After executing generated code, the receiver_reg and name_reg
356// may be clobbered.
357void StubCompiler::GenerateStoreField(MacroAssembler* masm,
358 Builtins::Name storage_extend,
359 JSObject* object,
360 int index,
361 Map* transition,
362 Register receiver_reg,
363 Register name_reg,
364 Register scratch,
365 Label* miss_label) {
366 // r0 : value
367 Label exit;
368
369 // Check that the receiver isn't a smi.
370 __ tst(receiver_reg, Operand(kSmiTagMask));
371 __ b(eq, miss_label);
372
373 // Check that the map of the receiver hasn't changed.
374 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
375 __ cmp(scratch, Operand(Handle<Map>(object->map())));
376 __ b(ne, miss_label);
377
378 // Perform global security token check if needed.
379 if (object->IsJSGlobalProxy()) {
380 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
381 }
382
383 // Stub never generated for non-global objects that require access
384 // checks.
385 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
386
387 // Perform map transition for the receiver if necessary.
388 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
389 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000390 // We jump to a runtime call that extends the properties array.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000391 __ mov(r2, Operand(Handle<Map>(transition)));
392 // Please note, if we implement keyed store for arm we need
393 // to call the Builtins::KeyedStoreIC_ExtendStorage.
394 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage));
395 __ Jump(ic, RelocInfo::CODE_TARGET);
396 return;
397 }
398
399 if (transition != NULL) {
400 // Update the map of the object; no write barrier updating is
401 // needed because the map is never in new space.
402 __ mov(ip, Operand(Handle<Map>(transition)));
403 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
404 }
405
406 // Adjust for the number of properties stored in the object. Even in the
407 // face of a transition we can use the old map here because the size of the
408 // object and the number of in-object properties is not going to change.
409 index -= object->map()->inobject_properties();
410
411 if (index < 0) {
412 // Set the property straight into the object.
413 int offset = object->map()->instance_size() + (index * kPointerSize);
414 __ str(r0, FieldMemOperand(receiver_reg, offset));
415
416 // Skip updating write barrier if storing a smi.
417 __ tst(r0, Operand(kSmiTagMask));
418 __ b(eq, &exit);
419
420 // Update the write barrier for the array address.
421 // Pass the value being stored in the now unused name_reg.
422 __ mov(name_reg, Operand(offset));
423 __ RecordWrite(receiver_reg, name_reg, scratch);
424 } else {
425 // Write to the properties array.
426 int offset = index * kPointerSize + Array::kHeaderSize;
427 // Get the properties array
428 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
429 __ str(r0, FieldMemOperand(scratch, offset));
430
431 // Skip updating write barrier if storing a smi.
432 __ tst(r0, Operand(kSmiTagMask));
433 __ b(eq, &exit);
434
435 // Update the write barrier for the array address.
436 // Ok to clobber receiver_reg and name_reg, since we return.
437 __ mov(name_reg, Operand(offset));
438 __ RecordWrite(scratch, name_reg, receiver_reg);
439 }
440
441 // Return the value (register r0).
442 __ bind(&exit);
443 __ Ret();
444}
445
446
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000447void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
448 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
449 Code* code = NULL;
450 if (kind == Code::LOAD_IC) {
451 code = Builtins::builtin(Builtins::LoadIC_Miss);
452 } else {
453 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
454 }
455
456 Handle<Code> ic(code);
457 __ Jump(ic, RelocInfo::CODE_TARGET);
458}
459
460
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461#undef __
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000462#define __ ACCESS_MASM(masm())
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000463
464
465Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000466 // ----------- S t a t e -------------
467 // -- r1: function
468 // -- lr: return address
469 // -----------------------------------
470
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000471 // Enter an internal frame.
472 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000473
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000474 // Preserve the function.
475 __ push(r1);
476
477 // Push the function on the stack as the argument to the runtime function.
478 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000479 __ CallRuntime(Runtime::kLazyCompile, 1);
480
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000481 // Calculate the entry point.
482 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000483
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000484 // Restore saved function.
485 __ pop(r1);
486
487 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000488 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000489
490 // Do a tail-call of the compiled function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000491 __ Jump(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000493 return GetCodeWithFlags(flags, "LazyCompileStub");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000494}
495
496
497Object* CallStubCompiler::CompileCallField(Object* object,
498 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000499 int index,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000500 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502 // -- lr: return address
503 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504 Label miss;
505
mads.s.ager31e71382008-08-13 09:32:07 +0000506 const int argc = arguments().immediate();
507
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000508 // Get the receiver of the function from the stack into r0.
509 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000510 // Check that the receiver isn't a smi.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000511 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512 __ b(eq, &miss);
513
514 // Do the right check and compute the holder register.
515 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000516 masm()->CheckMaps(JSObject::cast(object), r0, holder, r3, r2, &miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000517 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518
519 // Check that the function really is a function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000520 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000521 __ b(eq, &miss);
522 // Get the map.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000523 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000524 __ b(ne, &miss);
525
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000526 // Patch the receiver on the stack with the global proxy if
527 // necessary.
528 if (object->IsGlobalObject()) {
529 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
530 __ str(r3, MemOperand(sp, argc * kPointerSize));
531 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000532
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000533 // Invoke the function.
534 __ InvokeFunction(r1, arguments(), JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000535
536 // Handle call cache miss.
537 __ bind(&miss);
538 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000539 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540
541 // Return the generated code.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000542 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000543}
544
545
546Object* CallStubCompiler::CompileCallConstant(Object* object,
547 JSObject* holder,
548 JSFunction* function,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000549 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551 // -- lr: return address
552 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553 Label miss;
554
mads.s.ager31e71382008-08-13 09:32:07 +0000555 // Get the receiver from the stack
556 const int argc = arguments().immediate();
557 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
558
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559 // Check that the receiver isn't a smi.
560 if (check != NUMBER_CHECK) {
561 __ tst(r1, Operand(kSmiTagMask));
562 __ b(eq, &miss);
563 }
564
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000565 // Make sure that it's okay not to patch the on stack receiver
566 // unless we're doing a receiver map check.
567 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
568
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569 switch (check) {
570 case RECEIVER_MAP_CHECK:
571 // Check that the maps haven't changed.
572 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000573
574 // Patch the receiver on the stack with the global proxy if
575 // necessary.
576 if (object->IsGlobalObject()) {
577 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
578 __ str(r3, MemOperand(sp, argc * kPointerSize));
579 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580 break;
581
582 case STRING_CHECK:
583 // Check that the object is a two-byte string or a symbol.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000584 __ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000585 __ b(hs, &miss);
586 // Check that the maps starting from the prototype haven't changed.
587 GenerateLoadGlobalFunctionPrototype(masm(),
588 Context::STRING_FUNCTION_INDEX,
589 r2);
590 __ CheckMaps(JSObject::cast(object->GetPrototype()),
591 r2, holder, r3, r1, &miss);
592 break;
593
594 case NUMBER_CHECK: {
595 Label fast;
596 // Check that the object is a smi or a heap number.
597 __ tst(r1, Operand(kSmiTagMask));
598 __ b(eq, &fast);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000599 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600 __ b(ne, &miss);
601 __ bind(&fast);
602 // Check that the maps starting from the prototype haven't changed.
603 GenerateLoadGlobalFunctionPrototype(masm(),
604 Context::NUMBER_FUNCTION_INDEX,
605 r2);
606 __ CheckMaps(JSObject::cast(object->GetPrototype()),
607 r2, holder, r3, r1, &miss);
608 break;
609 }
610
611 case BOOLEAN_CHECK: {
612 Label fast;
613 // Check that the object is a boolean.
614 __ cmp(r1, Operand(Factory::true_value()));
615 __ b(eq, &fast);
616 __ cmp(r1, Operand(Factory::false_value()));
617 __ b(ne, &miss);
618 __ bind(&fast);
619 // Check that the maps starting from the prototype haven't changed.
620 GenerateLoadGlobalFunctionPrototype(masm(),
621 Context::BOOLEAN_FUNCTION_INDEX,
622 r2);
623 __ CheckMaps(JSObject::cast(object->GetPrototype()),
624 r2, holder, r3, r1, &miss);
625 break;
626 }
627
628 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
629 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
630 // Make sure object->elements()->map() != Heap::hash_table_map()
631 // Get the elements array of the object.
632 __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
633 // Check that the object is in fast mode (not dictionary).
634 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
635 __ cmp(r2, Operand(Factory::hash_table_map()));
636 __ b(eq, &miss);
637 break;
638
639 default:
640 UNREACHABLE();
641 }
642
643 // Get the function and setup the context.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000644 __ mov(r1, Operand(Handle<JSFunction>(function)));
645 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000646
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647 // Jump to the cached code (tail call).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000648 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 Handle<Code> code(function->code());
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000650 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +0000651 __ InvokeCode(code, expected, arguments(),
652 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000653
654 // Handle call cache miss.
655 __ bind(&miss);
656 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000657 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000658
659 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000660 String* function_name = NULL;
661 if (function->shared()->name()->IsString()) {
662 function_name = String::cast(function->shared()->name());
663 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000664 return GetCode(CONSTANT_FUNCTION, function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000665}
666
667
668Object* CallStubCompiler::CompileCallInterceptor(Object* object,
669 JSObject* holder,
670 String* name) {
671 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000672 // -- lr: return address
673 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000674 Label miss;
675
676 // TODO(1224669): Implement.
677
678 // Handle call cache miss.
679 __ bind(&miss);
680 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000681 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000682
683 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000684 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000685}
686
687
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000688Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
689 JSGlobalPropertyCell* cell,
690 JSFunction* function,
691 String* name) {
692 // ----------- S t a t e -------------
693 // -- lr: return address
694 // -----------------------------------
695 Label miss;
696
697 __ IncrementCounter(&Counters::call_global_inline, 1, r1, r3);
698
699 // Get the number of arguments.
700 const int argc = arguments().immediate();
701
702 // Check that the map of the global has not changed.
703 __ ldr(r2, MemOperand(sp, argc * kPointerSize));
704 __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
705 __ cmp(r3, Operand(Handle<Map>(object->map())));
706 __ b(ne, &miss);
707
708 // Get the value from the cell.
709 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
710 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
711
712 // Check that the cell contains the same function.
713 __ cmp(r1, Operand(Handle<JSFunction>(function)));
714 __ b(ne, &miss);
715
716 // Patch the receiver on the stack with the global proxy if
717 // necessary.
718 __ ldr(r3, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
719 __ str(r3, MemOperand(sp, argc * kPointerSize));
720
721 // Setup the context (function already in r1).
722 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
723
724 // Jump to the cached code (tail call).
725 ASSERT(function->is_compiled());
726 Handle<Code> code(function->code());
727 ParameterCount expected(function->shared()->formal_parameter_count());
728 __ InvokeCode(code, expected, arguments(),
729 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
730
731 // Handle call cache miss.
732 __ bind(&miss);
733 __ DecrementCounter(&Counters::call_global_inline, 1, r1, r3);
734 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
735 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
736 __ Jump(ic, RelocInfo::CODE_TARGET);
737
738 // Return the generated code.
739 return GetCode(NORMAL, name);
740}
741
742
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000743Object* StoreStubCompiler::CompileStoreField(JSObject* object,
744 int index,
745 Map* transition,
746 String* name) {
747 // ----------- S t a t e -------------
748 // -- r0 : value
749 // -- r2 : name
750 // -- lr : return address
751 // -- [sp] : receiver
752 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000753 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000754
755 // Get the receiver from the stack.
756 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
757
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000758 // name register might be clobbered.
759 GenerateStoreField(masm(),
760 Builtins::StoreIC_ExtendStorage,
761 object,
762 index,
763 transition,
764 r3, r2, r1,
765 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000766 __ bind(&miss);
767 __ mov(r2, Operand(Handle<String>(name))); // restore name
768 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000769 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000770
771 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000772 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773}
774
775
776Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
777 AccessorInfo* callback,
778 String* name) {
779 // ----------- S t a t e -------------
780 // -- r0 : value
781 // -- r2 : name
782 // -- lr : return address
783 // -- [sp] : receiver
784 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000785 Label miss;
786
787 // Get the object from the stack.
788 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
789
790 // Check that the object isn't a smi.
791 __ tst(r3, Operand(kSmiTagMask));
792 __ b(eq, &miss);
793
794 // Check that the map of the object hasn't changed.
795 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
796 __ cmp(r1, Operand(Handle<Map>(object->map())));
797 __ b(ne, &miss);
798
799 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000800 if (object->IsJSGlobalProxy()) {
801 __ CheckAccessGlobalProxy(r3, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000802 }
803
804 // Stub never generated for non-global objects that require access
805 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000806 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000807
808 __ ldr(ip, MemOperand(sp)); // receiver
809 __ push(ip);
810 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
811 __ push(ip);
812 __ push(r2); // name
813 __ push(r0); // value
814
mads.s.ager31e71382008-08-13 09:32:07 +0000815 // Do tail-call to the runtime system.
816 ExternalReference store_callback_property =
817 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
818 __ TailCallRuntime(store_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819
820 // Handle store cache miss.
821 __ bind(&miss);
822 __ mov(r2, Operand(Handle<String>(name))); // restore name
823 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000824 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000825
826 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000827 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000828}
829
830
831Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
832 String* name) {
833 // ----------- S t a t e -------------
834 // -- r0 : value
835 // -- r2 : name
836 // -- lr : return address
837 // -- [sp] : receiver
838 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839 Label miss;
840
841 // Get the object from the stack.
842 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
843
844 // Check that the object isn't a smi.
845 __ tst(r3, Operand(kSmiTagMask));
846 __ b(eq, &miss);
847
848 // Check that the map of the object hasn't changed.
849 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
850 __ cmp(r1, Operand(Handle<Map>(receiver->map())));
851 __ b(ne, &miss);
852
853 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000854 if (receiver->IsJSGlobalProxy()) {
855 __ CheckAccessGlobalProxy(r3, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000856 }
857
858 // Stub never generated for non-global objects that require access
859 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000860 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000861
862 __ ldr(ip, MemOperand(sp)); // receiver
863 __ push(ip);
864 __ push(r2); // name
865 __ push(r0); // value
866
mads.s.ager31e71382008-08-13 09:32:07 +0000867 // Do tail-call to the runtime system.
868 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000869 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000870 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871
872 // Handle store cache miss.
873 __ bind(&miss);
874 __ mov(r2, Operand(Handle<String>(name))); // restore name
875 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000876 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000877
878 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000879 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880}
881
882
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000883Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
884 JSGlobalPropertyCell* cell,
885 String* name) {
886 // ----------- S t a t e -------------
887 // -- r0 : value
888 // -- r2 : name
889 // -- lr : return address
890 // -- [sp] : receiver
891 // -----------------------------------
892 Label miss;
893
894 __ IncrementCounter(&Counters::named_store_global_inline, 1, r1, r3);
895
896 // Check that the map of the global has not changed.
897 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
898 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
899 __ cmp(r3, Operand(Handle<Map>(object->map())));
900 __ b(ne, &miss);
901
902 // Store the value in the cell.
903 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
904 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
905 __ mov(r1, Operand(JSGlobalPropertyCell::kValueOffset));
906 __ RecordWrite(r2, r1, r3);
907
908 __ Ret();
909
910 // Handle store cache miss.
911 __ bind(&miss);
912 __ DecrementCounter(&Counters::named_store_global_inline, 1, r1, r3);
913 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r1, r3);
914 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
915 __ Jump(ic, RelocInfo::CODE_TARGET);
916
917 // Return the generated code.
918 return GetCode(NORMAL, name);
919}
920
921
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000922Object* LoadStubCompiler::CompileLoadField(JSObject* object,
923 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000924 int index,
925 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000927 // -- r2 : name
928 // -- lr : return address
929 // -- [sp] : receiver
930 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931 Label miss;
932
mads.s.ager31e71382008-08-13 09:32:07 +0000933 __ ldr(r0, MemOperand(sp, 0));
934
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000935 GenerateLoadField(masm(), object, holder, r0, r3, r1, index, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000936 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000937 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000938
939 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000940 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000941}
942
943
944Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
945 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000946 AccessorInfo* callback,
947 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000948 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000949 // -- r2 : name
950 // -- lr : return address
951 // -- [sp] : receiver
952 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000953 Label miss;
954
mads.s.ager31e71382008-08-13 09:32:07 +0000955 __ ldr(r0, MemOperand(sp, 0));
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000956 GenerateLoadCallback(masm(), object, holder, r0, r2, r3, r1, callback, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000957 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000958 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000959
960 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000961 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000962}
963
964
965Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
966 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000967 Object* value,
968 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000969 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970 // -- r2 : name
971 // -- lr : return address
972 // -- [sp] : receiver
973 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000974 Label miss;
975
mads.s.ager31e71382008-08-13 09:32:07 +0000976 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000977
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000978 GenerateLoadConstant(masm(), object, holder, r0, r3, r1, value, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000979 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000980 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981
982 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000983 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984}
985
986
987Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
988 JSObject* holder,
989 String* name) {
990 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991 // -- r2 : name
992 // -- lr : return address
993 // -- [sp] : receiver
994 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000995 Label miss;
996
mads.s.ager31e71382008-08-13 09:32:07 +0000997 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998
ager@chromium.orge2902be2009-06-08 12:21:35 +0000999 GenerateLoadInterceptor(masm(),
1000 object,
1001 holder,
1002 holder->InterceptorPropertyLookupHint(name),
1003 r0,
1004 r2,
1005 r3,
1006 r1,
1007 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001008 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001009 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010
1011 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001012 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001013}
1014
1015
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001016Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
1017 JSGlobalPropertyCell* cell,
1018 String* name,
1019 bool is_dont_delete) {
1020 // ----------- S t a t e -------------
1021 // -- r2 : name
1022 // -- lr : return address
1023 // -- [sp] : receiver
1024 // -----------------------------------
1025 Label miss;
1026
1027 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
1028
1029 // Check that the map of the global has not changed.
1030 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
1031 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
1032 __ cmp(r3, Operand(Handle<Map>(object->map())));
1033 __ b(ne, &miss);
1034
1035 // Get the value from the cell.
1036 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1037 __ ldr(r0, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1038
1039 // Check for deleted property if property can actually be deleted.
1040 if (!is_dont_delete) {
1041 __ cmp(r0, Operand(Factory::the_hole_value()));
1042 __ b(eq, &miss);
1043 }
1044
1045 __ Ret();
1046
1047 __ bind(&miss);
1048 __ DecrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
1049 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1050 GenerateLoadMiss(masm(), Code::LOAD_IC);
1051
1052 // Return the generated code.
1053 return GetCode(NORMAL, name);
1054}
1055
1056
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057// TODO(1224671): IC stubs for keyed loads have not been implemented
1058// for ARM.
1059Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1060 JSObject* receiver,
1061 JSObject* holder,
1062 int index) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001063 // ----------- S t a t e -------------
1064 // -- lr : return address
1065 // -- sp[0] : key
1066 // -- sp[4] : receiver
1067 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001068 Label miss;
1069
1070 __ ldr(r2, MemOperand(sp, 0));
1071 __ ldr(r0, MemOperand(sp, kPointerSize));
1072
1073 __ cmp(r2, Operand(Handle<String>(name)));
1074 __ b(ne, &miss);
1075
1076 GenerateLoadField(masm(), receiver, holder, r0, r3, r1, index, &miss);
1077 __ bind(&miss);
1078 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1079
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001080 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001081}
1082
1083
1084Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1085 JSObject* receiver,
1086 JSObject* holder,
1087 AccessorInfo* callback) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001088 // ----------- S t a t e -------------
1089 // -- lr : return address
1090 // -- sp[0] : key
1091 // -- sp[4] : receiver
1092 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001093 Label miss;
1094
1095 __ ldr(r2, MemOperand(sp, 0));
1096 __ ldr(r0, MemOperand(sp, kPointerSize));
1097
1098 __ cmp(r2, Operand(Handle<String>(name)));
1099 __ b(ne, &miss);
1100
1101 GenerateLoadCallback(masm(), receiver, holder, r0, r2, r3,
1102 r1, callback, &miss);
1103 __ bind(&miss);
1104 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1105
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001106 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001107}
1108
1109
1110Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1111 JSObject* receiver,
1112 JSObject* holder,
1113 Object* value) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001114 // ----------- S t a t e -------------
1115 // -- lr : return address
1116 // -- sp[0] : key
1117 // -- sp[4] : receiver
1118 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001119 Label miss;
1120
1121 // Check the key is the cached one
1122 __ ldr(r2, MemOperand(sp, 0));
1123 __ ldr(r0, MemOperand(sp, kPointerSize));
1124
1125 __ cmp(r2, Operand(Handle<String>(name)));
1126 __ b(ne, &miss);
1127
1128 GenerateLoadConstant(masm(), receiver, holder, r0, r3, r1, value, &miss);
1129 __ bind(&miss);
1130 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1131
1132 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001133 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134}
1135
1136
1137Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1138 JSObject* holder,
1139 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001140 // ----------- S t a t e -------------
1141 // -- lr : return address
1142 // -- sp[0] : key
1143 // -- sp[4] : receiver
1144 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001145 Label miss;
1146
1147 // Check the key is the cached one
1148 __ ldr(r2, MemOperand(sp, 0));
1149 __ ldr(r0, MemOperand(sp, kPointerSize));
1150
1151 __ cmp(r2, Operand(Handle<String>(name)));
1152 __ b(ne, &miss);
1153
ager@chromium.orge2902be2009-06-08 12:21:35 +00001154 GenerateLoadInterceptor(masm(),
1155 receiver,
1156 holder,
1157 Smi::FromInt(JSObject::kLookupInHolder),
1158 r0,
1159 r2,
1160 r3,
1161 r1,
1162 &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001163 __ bind(&miss);
1164 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1165
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001166 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001167}
1168
1169
1170Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001171 // ----------- S t a t e -------------
1172 // -- lr : return address
1173 // -- sp[0] : key
1174 // -- sp[4] : receiver
1175 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001176 Label miss;
1177
1178 // Check the key is the cached one
1179 __ ldr(r2, MemOperand(sp, 0));
1180 __ ldr(r0, MemOperand(sp, kPointerSize));
1181
1182 __ cmp(r2, Operand(Handle<String>(name)));
1183 __ b(ne, &miss);
1184
1185 GenerateLoadArrayLength(masm(), r0, r3, &miss);
1186 __ bind(&miss);
1187 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1188
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001189 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190}
1191
1192
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001193Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001194 // ----------- S t a t e -------------
1195 // -- lr : return address
1196 // -- sp[0] : key
1197 // -- sp[4] : receiver
1198 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001199 Label miss;
1200 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1201
1202 __ ldr(r2, MemOperand(sp));
1203 __ ldr(r0, MemOperand(sp, kPointerSize)); // receiver
1204
1205 __ cmp(r2, Operand(Handle<String>(name)));
1206 __ b(ne, &miss);
1207
1208 GenerateLoadStringLength2(masm(), r0, r1, r3, &miss);
1209 __ bind(&miss);
1210 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1211
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001212 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1213
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001214 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215}
1216
1217
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001218// TODO(1224671): implement the fast case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001220 // ----------- S t a t e -------------
1221 // -- lr : return address
1222 // -- sp[0] : key
1223 // -- sp[4] : receiver
1224 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001225 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1226
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001227 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228}
1229
1230
1231Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1232 int index,
1233 Map* transition,
1234 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001235 // ----------- S t a t e -------------
1236 // -- r0 : value
1237 // -- r2 : name
1238 // -- lr : return address
1239 // -- [sp] : receiver
1240 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001241 Label miss;
1242
1243 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1244
1245 // Check that the name has not changed.
1246 __ cmp(r2, Operand(Handle<String>(name)));
1247 __ b(ne, &miss);
1248
1249 // Load receiver from the stack.
1250 __ ldr(r3, MemOperand(sp));
1251 // r1 is used as scratch register, r3 and r2 might be clobbered.
1252 GenerateStoreField(masm(),
1253 Builtins::StoreIC_ExtendStorage,
1254 object,
1255 index,
1256 transition,
1257 r3, r2, r1,
1258 &miss);
1259 __ bind(&miss);
1260
1261 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1262 __ mov(r2, Operand(Handle<String>(name))); // restore name register.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001263 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
1264 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001266 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001267 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001268}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269
1270
1271#undef __
1272
1273} } // namespace v8::internal