blob: 5bcc6b01fece02a5643b4ee10dbbe6822ec7679c [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 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
34namespace v8 { namespace internal {
35
36#define __ masm->
37
38
39static void ProbeTable(MacroAssembler* masm,
40 Code::Flags flags,
41 StubCache::Table table,
42 Register name,
43 Register offset) {
44 ExternalReference key_offset(SCTableReference::keyReference(table));
45 ExternalReference value_offset(SCTableReference::valueReference(table));
46
47 Label miss;
48
49 // Save the offset on the stack.
50 __ push(offset);
51
52 // Check that the key in the entry matches the name.
53 __ mov(ip, Operand(key_offset));
54 __ ldr(ip, MemOperand(ip, offset, LSL, 1));
55 __ cmp(name, Operand(ip));
56 __ b(ne, &miss);
57
58 // Get the code entry from the cache.
59 __ mov(ip, Operand(value_offset));
60 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
61
62 // Check that the flags match what we're looking for.
63 __ ldr(offset, FieldMemOperand(offset, Code::kFlagsOffset));
64 __ and_(offset, offset, Operand(~Code::kFlagsTypeMask));
65 __ cmp(offset, Operand(flags));
66 __ b(ne, &miss);
67
68 // Restore offset and re-load code entry from cache.
69 __ pop(offset);
70 __ mov(ip, Operand(value_offset));
71 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
72
73 // Jump to the first instruction in the code stub.
74 __ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
75 __ Jump(offset);
76
77 // Miss: Restore offset and fall through.
78 __ bind(&miss);
79 __ pop(offset);
80}
81
82
83void StubCache::GenerateProbe(MacroAssembler* masm,
84 Code::Flags flags,
85 Register receiver,
86 Register name,
87 Register scratch) {
88 Label miss;
89
90 // Make sure that code is valid. The shifting code relies on the
91 // entry size being 8.
92 ASSERT(sizeof(Entry) == 8);
93
94 // Make sure the flags does not name a specific type.
95 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
96
97 // Make sure that there are no register conflicts.
98 ASSERT(!scratch.is(receiver));
99 ASSERT(!scratch.is(name));
100
101 // Check that the receiver isn't a smi.
102 __ tst(receiver, Operand(kSmiTagMask));
103 __ b(eq, &miss);
104
105 // Get the map of the receiver and compute the hash.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000106 __ ldr(scratch, FieldMemOperand(name, String::kLengthOffset));
107 __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108 __ add(scratch, scratch, Operand(ip));
109 __ eor(scratch, scratch, Operand(flags));
110 __ and_(scratch,
111 scratch,
112 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
113
114 // Probe the primary table.
115 ProbeTable(masm, flags, kPrimary, name, scratch);
116
117 // Primary miss: Compute hash for secondary probe.
118 __ sub(scratch, scratch, Operand(name));
119 __ add(scratch, scratch, Operand(flags));
120 __ and_(scratch,
121 scratch,
122 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
123
124 // Probe the secondary table.
125 ProbeTable(masm, flags, kSecondary, name, scratch);
126
127 // Cache miss: Fall-through and let caller handle the miss by
128 // entering the runtime system.
129 __ bind(&miss);
130}
131
132
133void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
134 int index,
135 Register prototype) {
136 // Load the global or builtins object from the current context.
137 __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
138 // Load the global context from the global or builtins object.
139 __ ldr(prototype,
140 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
141 // Load the function from the global context.
142 __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
143 // Load the initial map. The global functions all have initial maps.
144 __ ldr(prototype,
145 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
146 // Load the prototype from the initial map.
147 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
148}
149
150
ager@chromium.org7c537e22008-10-16 08:43:32 +0000151// Load a fast property out of a holder object (src). In-object properties
152// are loaded directly otherwise the property is loaded from the properties
153// fixed array.
154void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
155 Register dst, Register src,
156 JSObject* holder, int index) {
157 // Adjust for the number of properties stored in the holder.
158 index -= holder->map()->inobject_properties();
159 if (index < 0) {
160 // Get the property straight out of the holder.
161 int offset = holder->map()->instance_size() + (index * kPointerSize);
162 __ ldr(dst, FieldMemOperand(src, offset));
163 } else {
164 // Calculate the offset into the properties array.
165 int offset = index * kPointerSize + Array::kHeaderSize;
166 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
167 __ ldr(dst, FieldMemOperand(dst, offset));
168 }
169}
170
171
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000172#undef __
173
174#define __ masm()->
175
176
177Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000178 // ----------- S t a t e -------------
179 // -- r1: function
180 // -- lr: return address
181 // -----------------------------------
182
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000183 HandleScope scope;
184
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000185 // Enter an internal frame.
186 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000187
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000188 // Preserve the function.
189 __ push(r1);
190
191 // Push the function on the stack as the argument to the runtime function.
192 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000193 __ CallRuntime(Runtime::kLazyCompile, 1);
194
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000195 // Calculate the entry point.
196 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000197
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000198 // Restore saved function.
199 __ pop(r1);
200
201 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000202 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000203
204 // Do a tail-call of the compiled function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000205 __ Jump(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000206
207 return GetCodeWithFlags(flags);
208}
209
210
211Object* CallStubCompiler::CompileCallField(Object* object,
212 JSObject* holder,
213 int index) {
214 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000215 // -- lr: return address
216 // -----------------------------------
217
218 HandleScope scope;
219 Label miss;
220
mads.s.ager31e71382008-08-13 09:32:07 +0000221 const int argc = arguments().immediate();
222
223 // Get the receiver of the function from the stack into r1.
224 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000225 // Check that the receiver isn't a smi.
226 __ tst(r1, Operand(kSmiTagMask));
227 __ b(eq, &miss);
228
229 // Do the right check and compute the holder register.
230 Register reg =
231 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000232 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000233
234 // Check that the function really is a function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000235 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236 __ b(eq, &miss);
237 // Get the map.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000238 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
240 __ cmp(r2, Operand(JS_FUNCTION_TYPE));
241 __ b(ne, &miss);
242
243 // Patch the function on the stack; 1 ~ receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000244 __ str(r1, MemOperand(sp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000245
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000246 // Invoke the function.
247 __ InvokeFunction(r1, arguments(), JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000248
249 // Handle call cache miss.
250 __ bind(&miss);
251 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000252 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000253
254 // Return the generated code.
255 return GetCode(FIELD);
256}
257
258
259Object* CallStubCompiler::CompileCallConstant(Object* object,
260 JSObject* holder,
261 JSFunction* function,
262 CheckType check) {
263 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000264 // -- lr: return address
265 // -----------------------------------
266
267 HandleScope scope;
268 Label miss;
269
mads.s.ager31e71382008-08-13 09:32:07 +0000270 // Get the receiver from the stack
271 const int argc = arguments().immediate();
272 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
273
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000274 // Check that the receiver isn't a smi.
275 if (check != NUMBER_CHECK) {
276 __ tst(r1, Operand(kSmiTagMask));
277 __ b(eq, &miss);
278 }
279
280 switch (check) {
281 case RECEIVER_MAP_CHECK:
282 // Check that the maps haven't changed.
283 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
284 break;
285
286 case STRING_CHECK:
287 // Check that the object is a two-byte string or a symbol.
288 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
289 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
290 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE));
291 __ b(hs, &miss);
292 // Check that the maps starting from the prototype haven't changed.
293 GenerateLoadGlobalFunctionPrototype(masm(),
294 Context::STRING_FUNCTION_INDEX,
295 r2);
296 __ CheckMaps(JSObject::cast(object->GetPrototype()),
297 r2, holder, r3, r1, &miss);
298 break;
299
300 case NUMBER_CHECK: {
301 Label fast;
302 // Check that the object is a smi or a heap number.
303 __ tst(r1, Operand(kSmiTagMask));
304 __ b(eq, &fast);
305 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
306 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
307 __ cmp(r2, Operand(HEAP_NUMBER_TYPE));
308 __ b(ne, &miss);
309 __ bind(&fast);
310 // Check that the maps starting from the prototype haven't changed.
311 GenerateLoadGlobalFunctionPrototype(masm(),
312 Context::NUMBER_FUNCTION_INDEX,
313 r2);
314 __ CheckMaps(JSObject::cast(object->GetPrototype()),
315 r2, holder, r3, r1, &miss);
316 break;
317 }
318
319 case BOOLEAN_CHECK: {
320 Label fast;
321 // Check that the object is a boolean.
322 __ cmp(r1, Operand(Factory::true_value()));
323 __ b(eq, &fast);
324 __ cmp(r1, Operand(Factory::false_value()));
325 __ b(ne, &miss);
326 __ bind(&fast);
327 // Check that the maps starting from the prototype haven't changed.
328 GenerateLoadGlobalFunctionPrototype(masm(),
329 Context::BOOLEAN_FUNCTION_INDEX,
330 r2);
331 __ CheckMaps(JSObject::cast(object->GetPrototype()),
332 r2, holder, r3, r1, &miss);
333 break;
334 }
335
336 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
337 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
338 // Make sure object->elements()->map() != Heap::hash_table_map()
339 // Get the elements array of the object.
340 __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
341 // Check that the object is in fast mode (not dictionary).
342 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
343 __ cmp(r2, Operand(Factory::hash_table_map()));
344 __ b(eq, &miss);
345 break;
346
347 default:
348 UNREACHABLE();
349 }
350
351 // Get the function and setup the context.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000352 __ mov(r1, Operand(Handle<JSFunction>(function)));
353 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354
355 // Patch the function on the stack; 1 ~ receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000356 __ str(r1, MemOperand(sp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000357
358 // Jump to the cached code (tail call).
359 Handle<Code> code(function->code());
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000360 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +0000361 __ InvokeCode(code, expected, arguments(),
362 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000363
364 // Handle call cache miss.
365 __ bind(&miss);
366 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000367 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368
369 // Return the generated code.
370 return GetCode(CONSTANT_FUNCTION);
371}
372
373
374Object* CallStubCompiler::CompileCallInterceptor(Object* object,
375 JSObject* holder,
376 String* name) {
377 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000378 // -- lr: return address
379 // -----------------------------------
380
381 HandleScope scope;
382 Label miss;
383
384 // TODO(1224669): Implement.
385
386 // Handle call cache miss.
387 __ bind(&miss);
388 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000389 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000390
391 // Return the generated code.
392 return GetCode(INTERCEPTOR);
393}
394
395
396Object* StoreStubCompiler::CompileStoreField(JSObject* object,
397 int index,
398 Map* transition,
399 String* name) {
400 // ----------- S t a t e -------------
401 // -- r0 : value
402 // -- r2 : name
403 // -- lr : return address
404 // -- [sp] : receiver
405 // -----------------------------------
406
407 HandleScope scope;
408 Label miss, exit;
409
410 // Get the receiver from the stack.
411 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
412
413 // Check that the receiver isn't a smi.
414 __ tst(r3, Operand(kSmiTagMask));
415 __ b(eq, &miss);
416
417 // Check that the map of the receiver hasn't changed.
418 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
419 __ cmp(r1, Operand(Handle<Map>(object->map())));
420 __ b(ne, &miss);
421
422 // Perform global security token check if needed.
423 if (object->IsJSGlobalObject()) {
424 __ CheckAccessGlobal(r3, r1, &miss);
425 }
426
427 // Stub never generated for non-global objects that require access
428 // checks.
429 ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
430
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431 // Perform map transition for the receiver if necessary.
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000432 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
433 // The properties must be extended before we can store the value.
434 // We jump to a runtime call that extends the propeties array.
435 __ mov(r2, Operand(Handle<Map>(transition)));
436 // Please note, if we implement keyed store for arm we need
437 // to call the Builtins::KeyedStoreIC_ExtendStorage.
438 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage));
439 __ Jump(ic, RelocInfo::CODE_TARGET);
440 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000441 // Adjust for the number of properties stored in the object. Even in the
442 // face of a transition we can use the old map here because the size of the
443 // object and the number of in-object properties is not going to change.
444 index -= object->map()->inobject_properties();
445
446 if (index >= 0) {
447 // Get the properties array
448 __ ldr(r1, FieldMemOperand(r3, JSObject::kPropertiesOffset));
449 }
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000450
451 if (transition != NULL) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000452 // Update the map of the object; no write barrier updating is
453 // needed because the map is never in new space.
454 __ mov(ip, Operand(Handle<Map>(transition)));
455 __ str(ip, FieldMemOperand(r3, HeapObject::kMapOffset));
456 }
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000457
ager@chromium.org7c537e22008-10-16 08:43:32 +0000458 if (index < 0) {
459 // Set the property straight into the object.
460 int offset = object->map()->instance_size() + (index * kPointerSize);
461 __ str(r0, FieldMemOperand(r3, offset));
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000462
ager@chromium.org7c537e22008-10-16 08:43:32 +0000463 // Skip updating write barrier if storing a smi.
464 __ tst(r0, Operand(kSmiTagMask));
465 __ b(eq, &exit);
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000466
ager@chromium.org7c537e22008-10-16 08:43:32 +0000467 // Update the write barrier for the array address.
468 __ mov(r1, Operand(offset));
469 __ RecordWrite(r3, r1, r2);
470 } else {
471 // Write to the properties array.
472 int offset = index * kPointerSize + Array::kHeaderSize;
473 __ str(r0, FieldMemOperand(r1, offset));
474
475 // Skip updating write barrier if storing a smi.
476 __ tst(r0, Operand(kSmiTagMask));
477 __ b(eq, &exit);
478
479 // Update the write barrier for the array address.
480 __ mov(r3, Operand(offset));
481 __ RecordWrite(r1, r3, r2); // OK to clobber r2, since we return
482 }
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000483
484 // Return the value (register r0).
485 __ bind(&exit);
486 __ Ret();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000488 // Handle store cache miss.
489 __ bind(&miss);
490 __ mov(r2, Operand(Handle<String>(name))); // restore name
491 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000492 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000493
494 // Return the generated code.
495 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
496}
497
498
499Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
500 AccessorInfo* callback,
501 String* name) {
502 // ----------- S t a t e -------------
503 // -- r0 : value
504 // -- r2 : name
505 // -- lr : return address
506 // -- [sp] : receiver
507 // -----------------------------------
508
509 HandleScope scope;
510 Label miss;
511
512 // Get the object from the stack.
513 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
514
515 // Check that the object isn't a smi.
516 __ tst(r3, Operand(kSmiTagMask));
517 __ b(eq, &miss);
518
519 // Check that the map of the object hasn't changed.
520 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
521 __ cmp(r1, Operand(Handle<Map>(object->map())));
522 __ b(ne, &miss);
523
524 // Perform global security token check if needed.
525 if (object->IsJSGlobalObject()) {
526 __ CheckAccessGlobal(r3, r1, &miss);
527 }
528
529 // Stub never generated for non-global objects that require access
530 // checks.
531 ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
532
533 __ ldr(ip, MemOperand(sp)); // receiver
534 __ push(ip);
535 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
536 __ push(ip);
537 __ push(r2); // name
538 __ push(r0); // value
539
mads.s.ager31e71382008-08-13 09:32:07 +0000540 // Do tail-call to the runtime system.
541 ExternalReference store_callback_property =
542 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
543 __ TailCallRuntime(store_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000544
545 // Handle store cache miss.
546 __ bind(&miss);
547 __ mov(r2, Operand(Handle<String>(name))); // restore name
548 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000549 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550
551 // Return the generated code.
552 return GetCode(CALLBACKS);
553}
554
555
556Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
557 String* name) {
558 // ----------- S t a t e -------------
559 // -- r0 : value
560 // -- r2 : name
561 // -- lr : return address
562 // -- [sp] : receiver
563 // -----------------------------------
564
565 HandleScope scope;
566 Label miss;
567
568 // Get the object from the stack.
569 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
570
571 // Check that the object isn't a smi.
572 __ tst(r3, Operand(kSmiTagMask));
573 __ b(eq, &miss);
574
575 // Check that the map of the object hasn't changed.
576 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
577 __ cmp(r1, Operand(Handle<Map>(receiver->map())));
578 __ b(ne, &miss);
579
580 // Perform global security token check if needed.
581 if (receiver->IsJSGlobalObject()) {
582 __ CheckAccessGlobal(r3, r1, &miss);
583 }
584
585 // Stub never generated for non-global objects that require access
586 // checks.
587 ASSERT(receiver->IsJSGlobalObject() || !receiver->IsAccessCheckNeeded());
588
589 __ ldr(ip, MemOperand(sp)); // receiver
590 __ push(ip);
591 __ push(r2); // name
592 __ push(r0); // value
593
mads.s.ager31e71382008-08-13 09:32:07 +0000594 // Do tail-call to the runtime system.
595 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000596 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000597 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000598
599 // Handle store cache miss.
600 __ bind(&miss);
601 __ mov(r2, Operand(Handle<String>(name))); // restore name
602 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000603 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000604
605 // Return the generated code.
606 return GetCode(INTERCEPTOR);
607}
608
609
610Object* LoadStubCompiler::CompileLoadField(JSObject* object,
611 JSObject* holder,
612 int index) {
613 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000614 // -- r2 : name
615 // -- lr : return address
616 // -- [sp] : receiver
617 // -----------------------------------
618
619 HandleScope scope;
620 Label miss;
621
mads.s.ager31e71382008-08-13 09:32:07 +0000622 __ ldr(r0, MemOperand(sp, 0));
623
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 // Check that the receiver isn't a smi.
625 __ tst(r0, Operand(kSmiTagMask));
626 __ b(eq, &miss);
627
628 // Check that the maps haven't changed.
629 Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000630 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631 __ Ret();
632
633 // Handle load cache miss.
634 __ bind(&miss);
635 __ ldr(r0, MemOperand(sp)); // restore receiver
636 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000637 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638
639 // Return the generated code.
640 return GetCode(FIELD);
641}
642
643
644Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
645 JSObject* holder,
646 AccessorInfo* callback) {
647 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648 // -- r2 : name
649 // -- lr : return address
650 // -- [sp] : receiver
651 // -----------------------------------
652
653 HandleScope scope;
654 Label miss;
655
mads.s.ager31e71382008-08-13 09:32:07 +0000656 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657 // Check that the receiver isn't a smi.
658 __ tst(r0, Operand(kSmiTagMask));
659 __ b(eq, &miss);
660
661 // Check that the maps haven't changed.
662 Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
663
664 // Push the arguments on the JS stack of the caller.
665 __ push(r0); // receiver
666 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
667 __ push(ip);
668 __ push(r2); // name
669 __ push(reg); // holder
670
mads.s.ager31e71382008-08-13 09:32:07 +0000671 // Do tail-call to the runtime system.
672 ExternalReference load_callback_property =
673 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
674 __ TailCallRuntime(load_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000675
676 // Handle load cache miss.
677 __ bind(&miss);
678 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000679 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680
681 // Return the generated code.
682 return GetCode(CALLBACKS);
683}
684
685
686Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
687 JSObject* holder,
688 Object* value) {
689 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000690 // -- r2 : name
691 // -- lr : return address
692 // -- [sp] : receiver
693 // -----------------------------------
694
695 HandleScope scope;
696 Label miss;
697
mads.s.ager31e71382008-08-13 09:32:07 +0000698 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000699 // Check that the receiver isn't a smi.
700 __ tst(r0, Operand(kSmiTagMask));
701 __ b(eq, &miss);
702
703 // Check that the maps haven't changed.
704 Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
705
706 // Return the constant value.
707 __ mov(r0, Operand(Handle<Object>(value)));
708 __ Ret();
709
710 // Handle load cache miss.
711 __ bind(&miss);
712 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000713 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000714
715 // Return the generated code.
716 return GetCode(CONSTANT_FUNCTION);
717}
718
719
720Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
721 JSObject* holder,
722 String* name) {
723 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000724 // -- r2 : name
725 // -- lr : return address
726 // -- [sp] : receiver
727 // -----------------------------------
728
729 HandleScope scope;
730 Label miss;
731
mads.s.ager31e71382008-08-13 09:32:07 +0000732 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000733 // Check that the receiver isn't a smi.
734 __ tst(r0, Operand(kSmiTagMask));
735 __ b(eq, &miss);
736
737 // Check that the maps haven't changed.
738 Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
739
740 // Push the arguments on the JS stack of the caller.
741 __ push(r0); // receiver
742 __ push(reg); // holder
743 __ push(r2); // name
744
mads.s.ager31e71382008-08-13 09:32:07 +0000745 // Do tail-call to the runtime system.
746 ExternalReference load_ic_property =
747 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
748 __ TailCallRuntime(load_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000749
750 // Handle load cache miss.
751 __ bind(&miss);
752 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000753 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000754
755 // Return the generated code.
756 return GetCode(INTERCEPTOR);
757}
758
759
760// TODO(1224671): IC stubs for keyed loads have not been implemented
761// for ARM.
762Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
763 JSObject* receiver,
764 JSObject* holder,
765 int index) {
766 UNIMPLEMENTED();
767 return Heap::undefined_value();
768}
769
770
771Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
772 JSObject* receiver,
773 JSObject* holder,
774 AccessorInfo* callback) {
775 UNIMPLEMENTED();
776 return Heap::undefined_value();
777}
778
779
780Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
781 JSObject* receiver,
782 JSObject* holder,
783 Object* value) {
784 UNIMPLEMENTED();
785 return Heap::undefined_value();
786}
787
788
789Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
790 JSObject* holder,
791 String* name) {
792 UNIMPLEMENTED();
793 return Heap::undefined_value();
794}
795
796
797Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
798 UNIMPLEMENTED();
799 return Heap::undefined_value();
800}
801
802
803Object* KeyedLoadStubCompiler::CompileLoadShortStringLength(String* name) {
804 UNIMPLEMENTED();
805 return Heap::undefined_value();
806}
807
808
809Object* KeyedLoadStubCompiler::CompileLoadMediumStringLength(String* name) {
810 UNIMPLEMENTED();
811 return Heap::undefined_value();
812}
813
814
815Object* KeyedLoadStubCompiler::CompileLoadLongStringLength(String* name) {
816 UNIMPLEMENTED();
817 return Heap::undefined_value();
818}
819
820
821Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
822 UNIMPLEMENTED();
823 return Heap::undefined_value();
824}
825
826
827Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
828 int index,
829 Map* transition,
830 String* name) {
831 UNIMPLEMENTED();
832 return Heap::undefined_value();
833}
834
835
836
837#undef __
838
839} } // namespace v8::internal