blob: 708ac3cdf4a1cd4d1c667648f6e3f534334c703e [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.
106 __ ldr(scratch, FieldMemOperand(receiver, HeapObject::kMapOffset));
107 __ ldr(ip, FieldMemOperand(name, String::kLengthOffset));
108 __ 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
151#undef __
152
153#define __ masm()->
154
155
156Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000157 // ----------- S t a t e -------------
158 // -- r1: function
159 // -- lr: return address
160 // -----------------------------------
161
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000162 HandleScope scope;
163
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000164 // Enter an internal frame.
165 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000166
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000167 // Preserve the function.
168 __ push(r1);
169
170 // Push the function on the stack as the argument to the runtime function.
171 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000172 __ CallRuntime(Runtime::kLazyCompile, 1);
173
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000174 // Calculate the entry point.
175 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000176
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000177 // Restore saved function.
178 __ pop(r1);
179
180 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000181 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000182
183 // Do a tail-call of the compiled function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000184 __ Jump(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000185
186 return GetCodeWithFlags(flags);
187}
188
189
190Object* CallStubCompiler::CompileCallField(Object* object,
191 JSObject* holder,
192 int index) {
193 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000194 // -- lr: return address
195 // -----------------------------------
196
197 HandleScope scope;
198 Label miss;
199
mads.s.ager31e71382008-08-13 09:32:07 +0000200 const int argc = arguments().immediate();
201
202 // Get the receiver of the function from the stack into r1.
203 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204 // Check that the receiver isn't a smi.
205 __ tst(r1, Operand(kSmiTagMask));
206 __ b(eq, &miss);
207
208 // Do the right check and compute the holder register.
209 Register reg =
210 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
211
212 // Get the properties array of the holder and get the function from the field.
213 int offset = index * kPointerSize + Array::kHeaderSize;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000214 __ ldr(r1, FieldMemOperand(reg, JSObject::kPropertiesOffset));
215 __ ldr(r1, FieldMemOperand(r1, offset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000216
217 // Check that the function really is a function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000218 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000219 __ b(eq, &miss);
220 // Get the map.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000221 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
223 __ cmp(r2, Operand(JS_FUNCTION_TYPE));
224 __ b(ne, &miss);
225
226 // Patch the function on the stack; 1 ~ receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000227 __ str(r1, MemOperand(sp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000228
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000229 // Invoke the function.
230 __ InvokeFunction(r1, arguments(), JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000231
232 // Handle call cache miss.
233 __ bind(&miss);
234 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000235 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236
237 // Return the generated code.
238 return GetCode(FIELD);
239}
240
241
242Object* CallStubCompiler::CompileCallConstant(Object* object,
243 JSObject* holder,
244 JSFunction* function,
245 CheckType check) {
246 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000247 // -- lr: return address
248 // -----------------------------------
249
250 HandleScope scope;
251 Label miss;
252
mads.s.ager31e71382008-08-13 09:32:07 +0000253 // Get the receiver from the stack
254 const int argc = arguments().immediate();
255 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
256
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000257 // Check that the receiver isn't a smi.
258 if (check != NUMBER_CHECK) {
259 __ tst(r1, Operand(kSmiTagMask));
260 __ b(eq, &miss);
261 }
262
263 switch (check) {
264 case RECEIVER_MAP_CHECK:
265 // Check that the maps haven't changed.
266 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
267 break;
268
269 case STRING_CHECK:
270 // Check that the object is a two-byte string or a symbol.
271 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
272 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
273 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE));
274 __ b(hs, &miss);
275 // Check that the maps starting from the prototype haven't changed.
276 GenerateLoadGlobalFunctionPrototype(masm(),
277 Context::STRING_FUNCTION_INDEX,
278 r2);
279 __ CheckMaps(JSObject::cast(object->GetPrototype()),
280 r2, holder, r3, r1, &miss);
281 break;
282
283 case NUMBER_CHECK: {
284 Label fast;
285 // Check that the object is a smi or a heap number.
286 __ tst(r1, Operand(kSmiTagMask));
287 __ b(eq, &fast);
288 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
289 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
290 __ cmp(r2, Operand(HEAP_NUMBER_TYPE));
291 __ b(ne, &miss);
292 __ bind(&fast);
293 // Check that the maps starting from the prototype haven't changed.
294 GenerateLoadGlobalFunctionPrototype(masm(),
295 Context::NUMBER_FUNCTION_INDEX,
296 r2);
297 __ CheckMaps(JSObject::cast(object->GetPrototype()),
298 r2, holder, r3, r1, &miss);
299 break;
300 }
301
302 case BOOLEAN_CHECK: {
303 Label fast;
304 // Check that the object is a boolean.
305 __ cmp(r1, Operand(Factory::true_value()));
306 __ b(eq, &fast);
307 __ cmp(r1, Operand(Factory::false_value()));
308 __ b(ne, &miss);
309 __ bind(&fast);
310 // Check that the maps starting from the prototype haven't changed.
311 GenerateLoadGlobalFunctionPrototype(masm(),
312 Context::BOOLEAN_FUNCTION_INDEX,
313 r2);
314 __ CheckMaps(JSObject::cast(object->GetPrototype()),
315 r2, holder, r3, r1, &miss);
316 break;
317 }
318
319 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
320 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
321 // Make sure object->elements()->map() != Heap::hash_table_map()
322 // Get the elements array of the object.
323 __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
324 // Check that the object is in fast mode (not dictionary).
325 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
326 __ cmp(r2, Operand(Factory::hash_table_map()));
327 __ b(eq, &miss);
328 break;
329
330 default:
331 UNREACHABLE();
332 }
333
334 // Get the function and setup the context.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000335 __ mov(r1, Operand(Handle<JSFunction>(function)));
336 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337
338 // Patch the function on the stack; 1 ~ receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000339 __ str(r1, MemOperand(sp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340
341 // Jump to the cached code (tail call).
342 Handle<Code> code(function->code());
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000343 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +0000344 __ InvokeCode(code, expected, arguments(),
345 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000346
347 // Handle call cache miss.
348 __ bind(&miss);
349 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000350 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000351
352 // Return the generated code.
353 return GetCode(CONSTANT_FUNCTION);
354}
355
356
357Object* CallStubCompiler::CompileCallInterceptor(Object* object,
358 JSObject* holder,
359 String* name) {
360 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 // -- lr: return address
362 // -----------------------------------
363
364 HandleScope scope;
365 Label miss;
366
367 // TODO(1224669): Implement.
368
369 // Handle call cache miss.
370 __ bind(&miss);
371 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000372 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000373
374 // Return the generated code.
375 return GetCode(INTERCEPTOR);
376}
377
378
379Object* StoreStubCompiler::CompileStoreField(JSObject* object,
380 int index,
381 Map* transition,
382 String* name) {
383 // ----------- S t a t e -------------
384 // -- r0 : value
385 // -- r2 : name
386 // -- lr : return address
387 // -- [sp] : receiver
388 // -----------------------------------
389
390 HandleScope scope;
391 Label miss, exit;
392
393 // Get the receiver from the stack.
394 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
395
396 // Check that the receiver isn't a smi.
397 __ tst(r3, Operand(kSmiTagMask));
398 __ b(eq, &miss);
399
400 // Check that the map of the receiver hasn't changed.
401 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
402 __ cmp(r1, Operand(Handle<Map>(object->map())));
403 __ b(ne, &miss);
404
405 // Perform global security token check if needed.
406 if (object->IsJSGlobalObject()) {
407 __ CheckAccessGlobal(r3, r1, &miss);
408 }
409
410 // Stub never generated for non-global objects that require access
411 // checks.
412 ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
413
414 // Get the properties array
415 __ ldr(r1, FieldMemOperand(r3, JSObject::kPropertiesOffset));
416
417 // Perform map transition for the receiver if necessary.
418 if (transition != NULL) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000419 if (object->map()->unused_property_fields() == 0) {
420 // The properties must be extended before we can store the value.
421 // We jump to a runtime call that extends the propeties array.
422 __ mov(r2, Operand(Handle<Map>(transition)));
423 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage));
424 __ Jump(ic, RelocInfo::CODE_TARGET);
425 } else {
426 // Update the map of the object; no write barrier updating is
427 // needed because the map is never in new space.
428 __ mov(ip, Operand(Handle<Map>(transition)));
429 __ str(ip, FieldMemOperand(r3, HeapObject::kMapOffset));
430 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431 }
432
433 // Write to the properties array.
434 int offset = index * kPointerSize + Array::kHeaderSize;
435 __ str(r0, FieldMemOperand(r1, offset));
436
437 // Skip updating write barrier if storing a smi.
438 __ tst(r0, Operand(kSmiTagMask));
439 __ b(eq, &exit);
440
441 // Update the write barrier for the array address.
442 __ mov(r3, Operand(offset));
443 __ RecordWrite(r1, r3, r2); // OK to clobber r2, since we return
444
445 // Return the value (register r0).
446 __ bind(&exit);
447 __ Ret();
448
449 // Handle store cache miss.
450 __ bind(&miss);
451 __ mov(r2, Operand(Handle<String>(name))); // restore name
452 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000453 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000454
455 // Return the generated code.
456 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
457}
458
459
460Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
461 AccessorInfo* callback,
462 String* name) {
463 // ----------- S t a t e -------------
464 // -- r0 : value
465 // -- r2 : name
466 // -- lr : return address
467 // -- [sp] : receiver
468 // -----------------------------------
469
470 HandleScope scope;
471 Label miss;
472
473 // Get the object from the stack.
474 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
475
476 // Check that the object isn't a smi.
477 __ tst(r3, Operand(kSmiTagMask));
478 __ b(eq, &miss);
479
480 // Check that the map of the object hasn't changed.
481 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
482 __ cmp(r1, Operand(Handle<Map>(object->map())));
483 __ b(ne, &miss);
484
485 // Perform global security token check if needed.
486 if (object->IsJSGlobalObject()) {
487 __ CheckAccessGlobal(r3, r1, &miss);
488 }
489
490 // Stub never generated for non-global objects that require access
491 // checks.
492 ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
493
494 __ ldr(ip, MemOperand(sp)); // receiver
495 __ push(ip);
496 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
497 __ push(ip);
498 __ push(r2); // name
499 __ push(r0); // value
500
mads.s.ager31e71382008-08-13 09:32:07 +0000501 // Do tail-call to the runtime system.
502 ExternalReference store_callback_property =
503 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
504 __ TailCallRuntime(store_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000505
506 // Handle store cache miss.
507 __ bind(&miss);
508 __ mov(r2, Operand(Handle<String>(name))); // restore name
509 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000510 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000511
512 // Return the generated code.
513 return GetCode(CALLBACKS);
514}
515
516
517Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
518 String* name) {
519 // ----------- S t a t e -------------
520 // -- r0 : value
521 // -- r2 : name
522 // -- lr : return address
523 // -- [sp] : receiver
524 // -----------------------------------
525
526 HandleScope scope;
527 Label miss;
528
529 // Get the object from the stack.
530 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
531
532 // Check that the object isn't a smi.
533 __ tst(r3, Operand(kSmiTagMask));
534 __ b(eq, &miss);
535
536 // Check that the map of the object hasn't changed.
537 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
538 __ cmp(r1, Operand(Handle<Map>(receiver->map())));
539 __ b(ne, &miss);
540
541 // Perform global security token check if needed.
542 if (receiver->IsJSGlobalObject()) {
543 __ CheckAccessGlobal(r3, r1, &miss);
544 }
545
546 // Stub never generated for non-global objects that require access
547 // checks.
548 ASSERT(receiver->IsJSGlobalObject() || !receiver->IsAccessCheckNeeded());
549
550 __ ldr(ip, MemOperand(sp)); // receiver
551 __ push(ip);
552 __ push(r2); // name
553 __ push(r0); // value
554
mads.s.ager31e71382008-08-13 09:32:07 +0000555 // Do tail-call to the runtime system.
556 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000558 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559
560 // Handle store cache miss.
561 __ bind(&miss);
562 __ mov(r2, Operand(Handle<String>(name))); // restore name
563 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000564 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000565
566 // Return the generated code.
567 return GetCode(INTERCEPTOR);
568}
569
570
571Object* LoadStubCompiler::CompileLoadField(JSObject* object,
572 JSObject* holder,
573 int index) {
574 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000575 // -- r2 : name
576 // -- lr : return address
577 // -- [sp] : receiver
578 // -----------------------------------
579
580 HandleScope scope;
581 Label miss;
582
mads.s.ager31e71382008-08-13 09:32:07 +0000583 __ ldr(r0, MemOperand(sp, 0));
584
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000585 // Check that the receiver isn't a smi.
586 __ tst(r0, Operand(kSmiTagMask));
587 __ b(eq, &miss);
588
589 // Check that the maps haven't changed.
590 Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
591
592 // Get the properties array of the holder.
593 __ ldr(r3, FieldMemOperand(reg, JSObject::kPropertiesOffset));
594
595 // Return the value from the properties array.
596 int offset = index * kPointerSize + Array::kHeaderSize;
597 __ ldr(r0, FieldMemOperand(r3, offset));
598 __ Ret();
599
600 // Handle load cache miss.
601 __ bind(&miss);
602 __ ldr(r0, MemOperand(sp)); // restore receiver
603 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000604 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000605
606 // Return the generated code.
607 return GetCode(FIELD);
608}
609
610
611Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
612 JSObject* holder,
613 AccessorInfo* callback) {
614 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615 // -- r2 : name
616 // -- lr : return address
617 // -- [sp] : receiver
618 // -----------------------------------
619
620 HandleScope scope;
621 Label miss;
622
mads.s.ager31e71382008-08-13 09:32:07 +0000623 __ ldr(r0, MemOperand(sp, 0));
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);
630
631 // Push the arguments on the JS stack of the caller.
632 __ push(r0); // receiver
633 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
634 __ push(ip);
635 __ push(r2); // name
636 __ push(reg); // holder
637
mads.s.ager31e71382008-08-13 09:32:07 +0000638 // Do tail-call to the runtime system.
639 ExternalReference load_callback_property =
640 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
641 __ TailCallRuntime(load_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642
643 // Handle load cache miss.
644 __ bind(&miss);
645 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000646 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647
648 // Return the generated code.
649 return GetCode(CALLBACKS);
650}
651
652
653Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
654 JSObject* holder,
655 Object* value) {
656 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657 // -- r2 : name
658 // -- lr : return address
659 // -- [sp] : receiver
660 // -----------------------------------
661
662 HandleScope scope;
663 Label miss;
664
mads.s.ager31e71382008-08-13 09:32:07 +0000665 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000666 // Check that the receiver isn't a smi.
667 __ tst(r0, Operand(kSmiTagMask));
668 __ b(eq, &miss);
669
670 // Check that the maps haven't changed.
671 Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
672
673 // Return the constant value.
674 __ mov(r0, Operand(Handle<Object>(value)));
675 __ Ret();
676
677 // Handle load cache miss.
678 __ bind(&miss);
679 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
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.
683 return GetCode(CONSTANT_FUNCTION);
684}
685
686
687Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
688 JSObject* holder,
689 String* name) {
690 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691 // -- r2 : name
692 // -- lr : return address
693 // -- [sp] : receiver
694 // -----------------------------------
695
696 HandleScope scope;
697 Label miss;
698
mads.s.ager31e71382008-08-13 09:32:07 +0000699 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700 // Check that the receiver isn't a smi.
701 __ tst(r0, Operand(kSmiTagMask));
702 __ b(eq, &miss);
703
704 // Check that the maps haven't changed.
705 Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
706
707 // Push the arguments on the JS stack of the caller.
708 __ push(r0); // receiver
709 __ push(reg); // holder
710 __ push(r2); // name
711
mads.s.ager31e71382008-08-13 09:32:07 +0000712 // Do tail-call to the runtime system.
713 ExternalReference load_ic_property =
714 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
715 __ TailCallRuntime(load_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000716
717 // Handle load cache miss.
718 __ bind(&miss);
719 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000720 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000721
722 // Return the generated code.
723 return GetCode(INTERCEPTOR);
724}
725
726
727// TODO(1224671): IC stubs for keyed loads have not been implemented
728// for ARM.
729Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
730 JSObject* receiver,
731 JSObject* holder,
732 int index) {
733 UNIMPLEMENTED();
734 return Heap::undefined_value();
735}
736
737
738Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
739 JSObject* receiver,
740 JSObject* holder,
741 AccessorInfo* callback) {
742 UNIMPLEMENTED();
743 return Heap::undefined_value();
744}
745
746
747Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
748 JSObject* receiver,
749 JSObject* holder,
750 Object* value) {
751 UNIMPLEMENTED();
752 return Heap::undefined_value();
753}
754
755
756Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
757 JSObject* holder,
758 String* name) {
759 UNIMPLEMENTED();
760 return Heap::undefined_value();
761}
762
763
764Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
765 UNIMPLEMENTED();
766 return Heap::undefined_value();
767}
768
769
770Object* KeyedLoadStubCompiler::CompileLoadShortStringLength(String* name) {
771 UNIMPLEMENTED();
772 return Heap::undefined_value();
773}
774
775
776Object* KeyedLoadStubCompiler::CompileLoadMediumStringLength(String* name) {
777 UNIMPLEMENTED();
778 return Heap::undefined_value();
779}
780
781
782Object* KeyedLoadStubCompiler::CompileLoadLongStringLength(String* name) {
783 UNIMPLEMENTED();
784 return Heap::undefined_value();
785}
786
787
788Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
789 UNIMPLEMENTED();
790 return Heap::undefined_value();
791}
792
793
794Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
795 int index,
796 Map* transition,
797 String* name) {
798 UNIMPLEMENTED();
799 return Heap::undefined_value();
800}
801
802
803
804#undef __
805
806} } // namespace v8::internal