blob: 425c51dcae557e4670f5a44563198b495ceb7061 [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,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000044 Register offset,
45 Register extra) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046 ExternalReference key_offset(SCTableReference::keyReference(table));
47 ExternalReference value_offset(SCTableReference::valueReference(table));
48
49 Label miss;
50
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000051 if (extra.is_valid()) {
52 // Get the code entry from the cache.
53 __ mov(extra, Operand::StaticArray(offset, times_2, value_offset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000055 // Check that the key in the entry matches the name.
56 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset));
57 __ j(not_equal, &miss, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000059 // Check that the flags match what we're looking for.
60 __ mov(offset, FieldOperand(extra, Code::kFlagsOffset));
61 __ and_(offset, ~Code::kFlagsNotUsedInLookup);
62 __ cmp(offset, flags);
63 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000065 // Jump to the first instruction in the code stub.
66 __ add(Operand(extra), Immediate(Code::kHeaderSize - kHeapObjectTag));
67 __ jmp(Operand(extra));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000069 __ bind(&miss);
70 } else {
71 // Save the offset on the stack.
72 __ push(offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000074 // Check that the key in the entry matches the name.
75 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset));
76 __ j(not_equal, &miss, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000078 // Get the code entry from the cache.
79 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
80
81 // Check that the flags match what we're looking for.
82 __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
83 __ and_(offset, ~Code::kFlagsNotUsedInLookup);
84 __ cmp(offset, flags);
85 __ j(not_equal, &miss);
86
87 // Restore offset and re-load code entry from cache.
88 __ pop(offset);
89 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
90
91 // Jump to the first instruction in the code stub.
92 __ add(Operand(offset), Immediate(Code::kHeaderSize - kHeapObjectTag));
93 __ jmp(Operand(offset));
94
95 // Pop at miss.
96 __ bind(&miss);
97 __ pop(offset);
98 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099}
100
101
102void StubCache::GenerateProbe(MacroAssembler* masm,
103 Code::Flags flags,
104 Register receiver,
105 Register name,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000106 Register scratch,
107 Register extra) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108 Label miss;
109
110 // Make sure that code is valid. The shifting code relies on the
111 // entry size being 8.
112 ASSERT(sizeof(Entry) == 8);
113
114 // Make sure the flags does not name a specific type.
115 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
116
117 // Make sure that there are no register conflicts.
118 ASSERT(!scratch.is(receiver));
119 ASSERT(!scratch.is(name));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000120 ASSERT(!extra.is(receiver));
121 ASSERT(!extra.is(name));
122 ASSERT(!extra.is(scratch));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123
124 // Check that the receiver isn't a smi.
125 __ test(receiver, Immediate(kSmiTagMask));
126 __ j(zero, &miss, not_taken);
127
128 // Get the map of the receiver and compute the hash.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000129 __ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000130 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000131 __ xor_(scratch, flags);
132 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
133
134 // Probe the primary table.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000135 ProbeTable(masm, flags, kPrimary, name, scratch, extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000136
137 // Primary miss: Compute hash for secondary probe.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000138 __ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000139 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
140 __ xor_(scratch, flags);
141 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000142 __ sub(scratch, Operand(name));
143 __ add(Operand(scratch), Immediate(flags));
144 __ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
145
146 // Probe the secondary table.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000147 ProbeTable(masm, flags, kSecondary, name, scratch, extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000148
149 // Cache miss: Fall-through and let caller handle the miss by
150 // entering the runtime system.
151 __ bind(&miss);
152}
153
154
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000155template <typename Pushable>
156static void PushInterceptorArguments(MacroAssembler* masm,
157 Register receiver,
158 Register holder,
159 Pushable name,
160 JSObject* holder_obj) {
161 __ push(receiver);
162 __ push(holder);
163 __ push(name);
164 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
165 __ mov(receiver, Immediate(Handle<Object>(interceptor)));
166 __ push(receiver);
167 __ push(FieldOperand(receiver, InterceptorInfo::kDataOffset));
168}
169
170
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000171void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
172 int index,
173 Register prototype) {
174 // Load the global or builtins object from the current context.
175 __ mov(prototype, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
176 // Load the global context from the global or builtins object.
177 __ mov(prototype,
178 FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
179 // Load the function from the global context.
180 __ mov(prototype, Operand(prototype, Context::SlotOffset(index)));
181 // Load the initial map. The global functions all have initial maps.
182 __ mov(prototype,
183 FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
184 // Load the prototype from the initial map.
185 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
186}
187
188
189void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
190 Register receiver,
191 Register scratch,
192 Label* miss_label) {
193 // Check that the receiver isn't a smi.
194 __ test(receiver, Immediate(kSmiTagMask));
195 __ j(zero, miss_label, not_taken);
196
197 // Check that the object is a JS array.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000198 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000199 __ j(not_equal, miss_label, not_taken);
200
201 // Load length directly from the JS array.
202 __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
203 __ ret(0);
204}
205
206
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000207// Generate code to check if an object is a string. If the object is
208// a string, the map's instance type is left in the scratch register.
209static void GenerateStringCheck(MacroAssembler* masm,
210 Register receiver,
211 Register scratch,
212 Label* smi,
213 Label* non_string_object) {
214 // Check that the object isn't a smi.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000215 __ test(receiver, Immediate(kSmiTagMask));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000216 __ j(zero, smi, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000218 // Check that the object is a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000219 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
220 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000221 ASSERT(kNotStringTag != 0);
222 __ test(scratch, Immediate(kNotStringTag));
223 __ j(not_zero, non_string_object, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224}
225
226
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000227void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
228 Register receiver,
229 Register scratch,
230 Label* miss) {
231 Label load_length, check_wrapper;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000232
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000233 // Check if the object is a string leaving the instance type in the
234 // scratch register.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000235 GenerateStringCheck(masm, receiver, scratch, miss, &check_wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000237 // Load length from the string and convert to a smi.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000238 __ bind(&load_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240 __ shl(eax, kSmiTagSize);
241 __ ret(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000242
243 // Check if the object is a JSValue wrapper.
244 __ bind(&check_wrapper);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000245 __ cmp(scratch, JS_VALUE_TYPE);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000246 __ j(not_equal, miss, not_taken);
247
248 // Check if the wrapped value is a string and load the length
249 // directly if it is.
250 __ mov(receiver, FieldOperand(receiver, JSValue::kValueOffset));
251 GenerateStringCheck(masm, receiver, scratch, miss, miss);
252 __ jmp(&load_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000253}
254
255
256void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
257 Register receiver,
258 Register scratch1,
259 Register scratch2,
260 Label* miss_label) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000261 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000262 __ mov(eax, Operand(scratch1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000263 __ ret(0);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000264}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265
ager@chromium.org7c537e22008-10-16 08:43:32 +0000266
267// Load a fast property out of a holder object (src). In-object properties
268// are loaded directly otherwise the property is loaded from the properties
269// fixed array.
270void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000271 Register dst, Register src,
272 JSObject* holder, int index) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000273 // Adjust for the number of properties stored in the holder.
274 index -= holder->map()->inobject_properties();
275 if (index < 0) {
276 // Get the property straight out of the holder.
277 int offset = holder->map()->instance_size() + (index * kPointerSize);
278 __ mov(dst, FieldOperand(src, offset));
279 } else {
280 // Calculate the offset into the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000281 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000282 __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
283 __ mov(dst, FieldOperand(dst, offset));
284 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000285}
286
287
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000288template <class Pushable>
289static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
290 Register receiver,
291 Register holder,
292 Pushable name,
293 JSObject* holder_obj) {
294 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
295
296 ExternalReference ref =
297 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
298 __ mov(eax, Immediate(5));
299 __ mov(ebx, Immediate(ref));
300
ager@chromium.orga1645e22009-09-09 19:27:10 +0000301 CEntryStub stub(1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000302 __ CallStub(&stub);
303}
304
305
306template <class Compiler>
307static void CompileLoadInterceptor(Compiler* compiler,
308 StubCompiler* stub_compiler,
309 MacroAssembler* masm,
310 JSObject* object,
311 JSObject* holder,
312 String* name,
313 LookupResult* lookup,
314 Register receiver,
315 Register scratch1,
316 Register scratch2,
317 Label* miss) {
318 ASSERT(holder->HasNamedInterceptor());
319 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
320
321 // Check that the receiver isn't a smi.
322 __ test(receiver, Immediate(kSmiTagMask));
323 __ j(zero, miss, not_taken);
324
325 // Check that the maps haven't changed.
326 Register reg =
327 stub_compiler->CheckPrototypes(object, receiver, holder,
328 scratch1, scratch2, name, miss);
329
330 if (lookup->IsValid() && lookup->IsCacheable()) {
331 compiler->CompileCacheable(masm,
332 stub_compiler,
333 receiver,
334 reg,
335 scratch1,
336 scratch2,
337 holder,
338 lookup,
339 name,
340 miss);
341 } else {
342 compiler->CompileRegular(masm,
343 receiver,
344 reg,
345 scratch2,
346 holder,
347 miss);
348 }
349}
350
351
352static void LookupPostInterceptor(JSObject* holder,
353 String* name,
354 LookupResult* lookup) {
355 holder->LocalLookupRealNamedProperty(name, lookup);
356 if (lookup->IsNotFound()) {
357 Object* proto = holder->GetPrototype();
358 if (proto != Heap::null_value()) {
359 proto->Lookup(name, lookup);
360 }
361 }
362}
363
364
365class LoadInterceptorCompiler BASE_EMBEDDED {
366 public:
367 explicit LoadInterceptorCompiler(Register name) : name_(name) {}
368
369 void CompileCacheable(MacroAssembler* masm,
370 StubCompiler* stub_compiler,
371 Register receiver,
372 Register holder,
373 Register scratch1,
374 Register scratch2,
375 JSObject* holder_obj,
376 LookupResult* lookup,
377 String* name,
378 Label* miss_label) {
379 AccessorInfo* callback = 0;
380 bool optimize = false;
381 // So far the most popular follow ups for interceptor loads are FIELD
382 // and CALLBACKS, so inline only them, other cases may be added
383 // later.
384 if (lookup->type() == FIELD) {
385 optimize = true;
386 } else if (lookup->type() == CALLBACKS) {
387 Object* callback_object = lookup->GetCallbackObject();
388 if (callback_object->IsAccessorInfo()) {
389 callback = AccessorInfo::cast(callback_object);
390 optimize = callback->getter() != NULL;
391 }
392 }
393
394 if (!optimize) {
395 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label);
396 return;
397 }
398
399 // Note: starting a frame here makes GC aware of pointers pushed below.
400 __ EnterInternalFrame();
401
402 if (lookup->type() == CALLBACKS) {
403 __ push(receiver);
404 }
405 __ push(holder);
406 __ push(name_);
407
408 CompileCallLoadPropertyWithInterceptor(masm,
409 receiver,
410 holder,
411 name_,
412 holder_obj);
413
414 Label interceptor_failed;
415 __ cmp(eax, Factory::no_interceptor_result_sentinel());
416 __ j(equal, &interceptor_failed);
417 __ LeaveInternalFrame();
418 __ ret(0);
419
420 __ bind(&interceptor_failed);
421 __ pop(name_);
422 __ pop(holder);
423 if (lookup->type() == CALLBACKS) {
424 __ pop(receiver);
425 }
426
427 __ LeaveInternalFrame();
428
429 if (lookup->type() == FIELD) {
430 holder = stub_compiler->CheckPrototypes(holder_obj, holder,
431 lookup->holder(), scratch1,
432 scratch2,
433 name,
434 miss_label);
435 stub_compiler->GenerateFastPropertyLoad(masm, eax,
436 holder, lookup->holder(),
437 lookup->GetFieldIndex());
438 __ ret(0);
439 } else {
440 ASSERT(lookup->type() == CALLBACKS);
441 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
442 ASSERT(callback != NULL);
443 ASSERT(callback->getter() != NULL);
444
445 Label cleanup;
446 __ pop(scratch2);
447 __ push(receiver);
448 __ push(scratch2);
449
450 holder = stub_compiler->CheckPrototypes(holder_obj, holder,
451 lookup->holder(), scratch1,
452 scratch2,
453 name,
454 &cleanup);
455
456 __ pop(scratch2); // save old return address
457 __ push(holder);
458 __ mov(holder, Immediate(Handle<AccessorInfo>(callback)));
459 __ push(holder);
460 __ push(FieldOperand(holder, AccessorInfo::kDataOffset));
461 __ push(name_);
462 __ push(scratch2); // restore old return address
463
464 ExternalReference ref =
465 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000466 __ TailCallRuntime(ref, 5, 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000467
468 __ bind(&cleanup);
469 __ pop(scratch1);
470 __ pop(scratch2);
471 __ push(scratch1);
472 }
473 }
474
475
476 void CompileRegular(MacroAssembler* masm,
477 Register receiver,
478 Register holder,
479 Register scratch,
480 JSObject* holder_obj,
481 Label* miss_label) {
482 __ pop(scratch); // save old return address
483 PushInterceptorArguments(masm, receiver, holder, name_, holder_obj);
484 __ push(scratch); // restore old return address
485
486 ExternalReference ref = ExternalReference(
487 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000488 __ TailCallRuntime(ref, 5, 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000489 }
490
491 private:
492 Register name_;
493};
494
495
496class CallInterceptorCompiler BASE_EMBEDDED {
497 public:
498 explicit CallInterceptorCompiler(const ParameterCount& arguments)
499 : arguments_(arguments), argc_(arguments.immediate()) {}
500
501 void CompileCacheable(MacroAssembler* masm,
502 StubCompiler* stub_compiler,
503 Register receiver,
504 Register holder,
505 Register scratch1,
506 Register scratch2,
507 JSObject* holder_obj,
508 LookupResult* lookup,
509 String* name,
510 Label* miss_label) {
511 JSFunction* function = 0;
512 bool optimize = false;
513 // So far the most popular case for failed interceptor is
514 // CONSTANT_FUNCTION sitting below.
515 if (lookup->type() == CONSTANT_FUNCTION) {
516 function = lookup->GetConstantFunction();
517 // JSArray holder is a special case for call constant function
518 // (see the corresponding code).
519 if (function->is_compiled() && !holder_obj->IsJSArray()) {
520 optimize = true;
521 }
522 }
523
524 if (!optimize) {
525 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label);
526 return;
527 }
528
529 __ EnterInternalFrame();
530 __ push(holder); // save the holder
531
532 CompileCallLoadPropertyWithInterceptor(
533 masm,
534 receiver,
535 holder,
536 // Under EnterInternalFrame this refers to name.
537 Operand(ebp, (argc_ + 3) * kPointerSize),
538 holder_obj);
539
540 __ pop(receiver); // restore holder
541 __ LeaveInternalFrame();
542
543 __ cmp(eax, Factory::no_interceptor_result_sentinel());
544 Label invoke;
545 __ j(not_equal, &invoke);
546
547 stub_compiler->CheckPrototypes(holder_obj, receiver,
548 lookup->holder(), scratch1,
549 scratch2,
550 name,
551 miss_label);
552 if (lookup->holder()->IsGlobalObject()) {
553 __ mov(edx, Operand(esp, (argc_ + 1) * kPointerSize));
554 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
555 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edx);
556 }
557
558 ASSERT(function->is_compiled());
559 // Get the function and setup the context.
560 __ mov(edi, Immediate(Handle<JSFunction>(function)));
561 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
562
563 // Jump to the cached code (tail call).
564 ASSERT(function->is_compiled());
565 Handle<Code> code(function->code());
566 ParameterCount expected(function->shared()->formal_parameter_count());
567 __ InvokeCode(code, expected, arguments_,
568 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
569
570 __ bind(&invoke);
571 }
572
573 void CompileRegular(MacroAssembler* masm,
574 Register receiver,
575 Register holder,
576 Register scratch,
577 JSObject* holder_obj,
578 Label* miss_label) {
579 __ EnterInternalFrame();
580
581 PushInterceptorArguments(masm,
582 receiver,
583 holder,
584 Operand(ebp, (argc_ + 3) * kPointerSize),
585 holder_obj);
586
587 ExternalReference ref = ExternalReference(
588 IC_Utility(IC::kLoadPropertyWithInterceptorForCall));
589 __ mov(eax, Immediate(5));
590 __ mov(ebx, Immediate(ref));
591
ager@chromium.orga1645e22009-09-09 19:27:10 +0000592 CEntryStub stub(1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000593 __ CallStub(&stub);
594
595 __ LeaveInternalFrame();
596 }
597
598 private:
599 const ParameterCount& arguments_;
600 int argc_;
601};
602
603
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000604void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
605 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
606 Code* code = NULL;
607 if (kind == Code::LOAD_IC) {
608 code = Builtins::builtin(Builtins::LoadIC_Miss);
609 } else {
610 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
611 }
612
613 Handle<Code> ic(code);
ager@chromium.org236ad962008-09-25 09:45:57 +0000614 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615}
616
617
618void StubCompiler::GenerateStoreField(MacroAssembler* masm,
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000619 Builtins::Name storage_extend,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 JSObject* object,
621 int index,
622 Map* transition,
623 Register receiver_reg,
624 Register name_reg,
625 Register scratch,
626 Label* miss_label) {
627 // Check that the object isn't a smi.
628 __ test(receiver_reg, Immediate(kSmiTagMask));
629 __ j(zero, miss_label, not_taken);
630
631 // Check that the map of the object hasn't changed.
632 __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
633 Immediate(Handle<Map>(object->map())));
634 __ j(not_equal, miss_label, not_taken);
635
636 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000637 if (object->IsJSGlobalProxy()) {
638 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639 }
640
641 // Stub never generated for non-global objects that require access
642 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000643 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000644
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000645 // Perform map transition for the receiver if necessary.
646 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
647 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000648 // We jump to a runtime call that extends the properties array.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000649 __ mov(ecx, Immediate(Handle<Map>(transition)));
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000650 Handle<Code> ic(Builtins::builtin(storage_extend));
651 __ jmp(ic, RelocInfo::CODE_TARGET);
652 return;
653 }
654
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000655 if (transition != NULL) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000656 // Update the map of the object; no write barrier updating is
657 // needed because the map is never in new space.
658 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
659 Immediate(Handle<Map>(transition)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000660 }
661
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000662 // Adjust for the number of properties stored in the object. Even in the
663 // face of a transition we can use the old map here because the size of the
664 // object and the number of in-object properties is not going to change.
665 index -= object->map()->inobject_properties();
666
ager@chromium.org7c537e22008-10-16 08:43:32 +0000667 if (index < 0) {
668 // Set the property straight into the object.
669 int offset = object->map()->instance_size() + (index * kPointerSize);
670 __ mov(FieldOperand(receiver_reg, offset), eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000671
ager@chromium.org7c537e22008-10-16 08:43:32 +0000672 // Update the write barrier for the array address.
673 // Pass the value being stored in the now unused name_reg.
674 __ mov(name_reg, Operand(eax));
675 __ RecordWrite(receiver_reg, offset, name_reg, scratch);
676 } else {
677 // Write to the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000678 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000679 // Get the properties array (optimistically).
680 __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000681 __ mov(FieldOperand(scratch, offset), eax);
682
683 // Update the write barrier for the array address.
684 // Pass the value being stored in the now unused name_reg.
685 __ mov(name_reg, Operand(eax));
686 __ RecordWrite(scratch, offset, name_reg, receiver_reg);
687 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000688
689 // Return the value (register eax).
690 __ ret(0);
691}
692
693
694#undef __
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000695#define __ ACCESS_MASM(masm())
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696
697
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000698Register StubCompiler::CheckPrototypes(JSObject* object,
699 Register object_reg,
700 JSObject* holder,
701 Register holder_reg,
702 Register scratch,
703 String* name,
704 Label* miss) {
705 // Check that the maps haven't changed.
706 Register result =
707 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
708
709 // If we've skipped any global objects, it's not enough to verify
710 // that their maps haven't changed.
711 while (object != holder) {
712 if (object->IsGlobalObject()) {
713 GlobalObject* global = GlobalObject::cast(object);
714 Object* probe = global->EnsurePropertyCell(name);
715 if (probe->IsFailure()) {
716 set_failure(Failure::cast(probe));
717 return result;
718 }
719 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
720 ASSERT(cell->value()->IsTheHole());
721 __ mov(scratch, Immediate(Handle<Object>(cell)));
722 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
723 Immediate(Factory::the_hole_value()));
724 __ j(not_equal, miss, not_taken);
725 }
726 object = JSObject::cast(object->GetPrototype());
727 }
728
729 // Return the register containin the holder.
730 return result;
731}
732
733
734void StubCompiler::GenerateLoadField(JSObject* object,
735 JSObject* holder,
736 Register receiver,
737 Register scratch1,
738 Register scratch2,
739 int index,
740 String* name,
741 Label* miss) {
742 // Check that the receiver isn't a smi.
743 __ test(receiver, Immediate(kSmiTagMask));
744 __ j(zero, miss, not_taken);
745
746 // Check the prototype chain.
747 Register reg =
748 CheckPrototypes(object, receiver, holder,
749 scratch1, scratch2, name, miss);
750
751 // Get the value from the properties.
752 GenerateFastPropertyLoad(masm(), eax, reg, holder, index);
753 __ ret(0);
754}
755
756
757void StubCompiler::GenerateLoadCallback(JSObject* object,
758 JSObject* holder,
759 Register receiver,
760 Register name_reg,
761 Register scratch1,
762 Register scratch2,
763 AccessorInfo* callback,
764 String* name,
765 Label* miss) {
766 // Check that the receiver isn't a smi.
767 __ test(receiver, Immediate(kSmiTagMask));
768 __ j(zero, miss, not_taken);
769
770 // Check that the maps haven't changed.
771 Register reg =
772 CheckPrototypes(object, receiver, holder,
773 scratch1, scratch2, name, miss);
774
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000775 Handle<AccessorInfo> callback_handle(callback);
776
777 Register other = reg.is(scratch1) ? scratch2 : scratch1;
778 __ EnterInternalFrame();
779 __ PushHandleScope(other);
780 // Push the stack address where the list of arguments ends
781 __ mov(other, esp);
782 __ sub(Operand(other), Immediate(2 * kPointerSize));
783 __ push(other);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000784 __ push(receiver); // receiver
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000785 __ push(reg); // holder
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000786 __ mov(other, Immediate(callback_handle));
787 __ push(other);
788 __ push(FieldOperand(other, AccessorInfo::kDataOffset)); // data
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000789 __ push(name_reg); // name
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000790 // Save a pointer to where we pushed the arguments pointer.
791 // This will be passed as the const Arguments& to the C++ callback.
792 __ mov(eax, esp);
793 __ add(Operand(eax), Immediate(5 * kPointerSize));
794 __ mov(ebx, esp);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000795
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000796 // Do call through the api.
797 ASSERT_EQ(6, ApiGetterEntryStub::kStackSpace);
798 Address getter_address = v8::ToCData<Address>(callback->getter());
799 ApiFunction fun(getter_address);
800 ApiGetterEntryStub stub(callback_handle, &fun);
801 __ CallStub(&stub);
802
803 // We need to avoid using eax since that now holds the result.
804 Register tmp = other.is(eax) ? reg : other;
805 __ PopHandleScope(eax, tmp);
806 __ LeaveInternalFrame();
807
808 __ ret(0);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000809}
810
811
812void StubCompiler::GenerateLoadConstant(JSObject* object,
813 JSObject* holder,
814 Register receiver,
815 Register scratch1,
816 Register scratch2,
817 Object* value,
818 String* name,
819 Label* miss) {
820 // Check that the receiver isn't a smi.
821 __ test(receiver, Immediate(kSmiTagMask));
822 __ j(zero, miss, not_taken);
823
824 // Check that the maps haven't changed.
825 Register reg =
826 CheckPrototypes(object, receiver, holder,
827 scratch1, scratch2, name, miss);
828
829 // Return the constant value.
830 __ mov(eax, Handle<Object>(value));
831 __ ret(0);
832}
833
834
835void StubCompiler::GenerateLoadInterceptor(JSObject* object,
836 JSObject* holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000837 LookupResult* lookup,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000838 Register receiver,
839 Register name_reg,
840 Register scratch1,
841 Register scratch2,
842 String* name,
843 Label* miss) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000844 LoadInterceptorCompiler compiler(name_reg);
845 CompileLoadInterceptor(&compiler,
846 this,
847 masm(),
848 object,
849 holder,
850 name,
851 lookup,
852 receiver,
853 scratch1,
854 scratch2,
855 miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000856}
857
858
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000859// TODO(1241006): Avoid having lazy compile stubs specialized by the
860// number of arguments. It is not needed anymore.
861Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000862 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000863 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000864
865 // Push a copy of the function onto the stack.
866 __ push(edi);
867
868 __ push(edi); // function is also the parameter to the runtime call
869 __ CallRuntime(Runtime::kLazyCompile, 1);
870 __ pop(edi);
871
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000872 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000873 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000874
875 // Do a tail-call of the compiled function.
876 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
877 __ jmp(Operand(ecx));
878
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000879 return GetCodeWithFlags(flags, "LazyCompileStub");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880}
881
882
883Object* CallStubCompiler::CompileCallField(Object* object,
884 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000885 int index,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000886 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000887 // ----------- S t a t e -------------
888 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889 Label miss;
890
891 // Get the receiver from the stack.
892 const int argc = arguments().immediate();
893 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
894
895 // Check that the receiver isn't a smi.
896 __ test(edx, Immediate(kSmiTagMask));
897 __ j(zero, &miss, not_taken);
898
899 // Do the right check and compute the holder register.
900 Register reg =
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000901 CheckPrototypes(JSObject::cast(object), edx, holder,
902 ebx, ecx, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000903
ager@chromium.org7c537e22008-10-16 08:43:32 +0000904 GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000905
906 // Check that the function really is a function.
907 __ test(edi, Immediate(kSmiTagMask));
908 __ j(zero, &miss, not_taken);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000909 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000910 __ j(not_equal, &miss, not_taken);
911
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000912 // Patch the receiver on the stack with the global proxy if
913 // necessary.
914 if (object->IsGlobalObject()) {
915 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
916 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
917 }
918
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000919 // Invoke the function.
920 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
921
922 // Handle call cache miss.
923 __ bind(&miss);
924 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000925 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926
927 // Return the generated code.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000928 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000929}
930
931
932Object* CallStubCompiler::CompileCallConstant(Object* object,
933 JSObject* holder,
934 JSFunction* function,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000935 String* name,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000936 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000937 // ----------- S t a t e -------------
938 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000939 Label miss;
940
941 // Get the receiver from the stack.
942 const int argc = arguments().immediate();
943 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
944
945 // Check that the receiver isn't a smi.
946 if (check != NUMBER_CHECK) {
947 __ test(edx, Immediate(kSmiTagMask));
948 __ j(zero, &miss, not_taken);
949 }
950
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000951 // Make sure that it's okay not to patch the on stack receiver
952 // unless we're doing a receiver map check.
953 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
954
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000955 switch (check) {
956 case RECEIVER_MAP_CHECK:
957 // Check that the maps haven't changed.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000958 CheckPrototypes(JSObject::cast(object), edx, holder,
959 ebx, ecx, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000960
961 // Patch the receiver on the stack with the global proxy if
962 // necessary.
963 if (object->IsGlobalObject()) {
964 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
965 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
966 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000967 break;
968
969 case STRING_CHECK:
970 // Check that the object is a two-byte string or a symbol.
971 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
972 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
973 __ cmp(ecx, FIRST_NONSTRING_TYPE);
974 __ j(above_equal, &miss, not_taken);
975 // Check that the maps starting from the prototype haven't changed.
976 GenerateLoadGlobalFunctionPrototype(masm(),
977 Context::STRING_FUNCTION_INDEX,
978 ecx);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000979 CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
980 ebx, edx, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981 break;
982
983 case NUMBER_CHECK: {
984 Label fast;
985 // Check that the object is a smi or a heap number.
986 __ test(edx, Immediate(kSmiTagMask));
987 __ j(zero, &fast, taken);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000988 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000989 __ j(not_equal, &miss, not_taken);
990 __ bind(&fast);
991 // Check that the maps starting from the prototype haven't changed.
992 GenerateLoadGlobalFunctionPrototype(masm(),
993 Context::NUMBER_FUNCTION_INDEX,
994 ecx);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000995 CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
996 ebx, edx, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 break;
998 }
999
1000 case BOOLEAN_CHECK: {
1001 Label fast;
1002 // Check that the object is a boolean.
1003 __ cmp(edx, Factory::true_value());
1004 __ j(equal, &fast, taken);
1005 __ cmp(edx, Factory::false_value());
1006 __ j(not_equal, &miss, not_taken);
1007 __ bind(&fast);
1008 // Check that the maps starting from the prototype haven't changed.
1009 GenerateLoadGlobalFunctionPrototype(masm(),
1010 Context::BOOLEAN_FUNCTION_INDEX,
1011 ecx);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001012 CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
1013 ebx, edx, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014 break;
1015 }
1016
1017 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001018 CheckPrototypes(JSObject::cast(object), edx, holder,
1019 ebx, ecx, name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001020 // Make sure object->HasFastElements().
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021 // Get the elements array of the object.
1022 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
1023 // Check that the object is in fast mode (not dictionary).
1024 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001025 Immediate(Factory::fixed_array_map()));
1026 __ j(not_equal, &miss, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001027 break;
1028
1029 default:
1030 UNREACHABLE();
1031 }
1032
1033 // Get the function and setup the context.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001034 __ mov(edi, Immediate(Handle<JSFunction>(function)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001035 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1036
1037 // Jump to the cached code (tail call).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001038 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001039 Handle<Code> code(function->code());
1040 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +00001041 __ InvokeCode(code, expected, arguments(),
1042 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001043
1044 // Handle call cache miss.
1045 __ bind(&miss);
1046 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +00001047 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048
1049 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001050 String* function_name = NULL;
1051 if (function->shared()->name()->IsString()) {
1052 function_name = String::cast(function->shared()->name());
1053 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001054 return GetCode(CONSTANT_FUNCTION, function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001055}
1056
1057
1058Object* CallStubCompiler::CompileCallInterceptor(Object* object,
1059 JSObject* holder,
1060 String* name) {
1061 // ----------- S t a t e -------------
1062 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063 Label miss;
1064
1065 // Get the number of arguments.
1066 const int argc = arguments().immediate();
1067
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001068 LookupResult lookup;
1069 LookupPostInterceptor(holder, name, &lookup);
1070
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071 // Get the receiver from the stack.
1072 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001073
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001074 CallInterceptorCompiler compiler(arguments());
1075 CompileLoadInterceptor(&compiler,
1076 this,
1077 masm(),
1078 JSObject::cast(object),
1079 holder,
1080 name,
1081 &lookup,
1082 edx,
1083 ebx,
1084 ecx,
1085 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001087 // Restore receiver.
1088 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001089
1090 // Check that the function really is a function.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001091 __ test(eax, Immediate(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001092 __ j(zero, &miss, not_taken);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001093 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001094 __ j(not_equal, &miss, not_taken);
1095
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001096 // Patch the receiver on the stack with the global proxy if
1097 // necessary.
1098 if (object->IsGlobalObject()) {
1099 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1100 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1101 }
1102
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001103 // Invoke the function.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001104 __ mov(edi, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001105 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
1106
1107 // Handle load cache miss.
1108 __ bind(&miss);
1109 Handle<Code> ic = ComputeCallMiss(argc);
ager@chromium.org236ad962008-09-25 09:45:57 +00001110 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111
1112 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001113 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001114}
1115
1116
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001117Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1118 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001119 JSGlobalPropertyCell* cell,
1120 JSFunction* function,
1121 String* name) {
1122 // ----------- S t a t e -------------
1123 // -----------------------------------
1124 Label miss;
1125
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001126 // Get the number of arguments.
1127 const int argc = arguments().immediate();
1128
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001129 // Get the receiver from the stack.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001130 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001131
1132 // If the object is the holder then we know that it's a global
1133 // object which can only happen for contextual calls. In this case,
1134 // the receiver cannot be a smi.
1135 if (object != holder) {
1136 __ test(edx, Immediate(kSmiTagMask));
1137 __ j(zero, &miss, not_taken);
1138 }
1139
1140 // Check that the maps haven't changed.
1141 CheckPrototypes(object, edx, holder, ebx, ecx, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001142
1143 // Get the value from the cell.
1144 __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
1145 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
1146
1147 // Check that the cell contains the same function.
1148 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function)));
1149 __ j(not_equal, &miss, not_taken);
1150
1151 // Patch the receiver on the stack with the global proxy.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001152 if (object->IsGlobalObject()) {
1153 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1154 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1155 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001156
1157 // Setup the context (function already in edi).
1158 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1159
1160 // Jump to the cached code (tail call).
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001161 __ IncrementCounter(&Counters::call_global_inline, 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001162 ASSERT(function->is_compiled());
1163 Handle<Code> code(function->code());
1164 ParameterCount expected(function->shared()->formal_parameter_count());
1165 __ InvokeCode(code, expected, arguments(),
1166 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1167
1168 // Handle call cache miss.
1169 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001170 __ IncrementCounter(&Counters::call_global_inline_miss, 1);
1171 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1172 __ jmp(ic, RelocInfo::CODE_TARGET);
1173
1174 // Return the generated code.
1175 return GetCode(NORMAL, name);
1176}
1177
1178
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1180 int index,
1181 Map* transition,
1182 String* name) {
1183 // ----------- S t a t e -------------
1184 // -- eax : value
1185 // -- ecx : name
1186 // -- esp[0] : return address
1187 // -- esp[4] : receiver
1188 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001189 Label miss;
1190
1191 // Get the object from the stack.
1192 __ mov(ebx, Operand(esp, 1 * kPointerSize));
1193
1194 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001195 GenerateStoreField(masm(),
1196 Builtins::StoreIC_ExtendStorage,
1197 object,
1198 index,
1199 transition,
1200 ebx, ecx, edx,
1201 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001202
1203 // Handle store cache miss.
1204 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001205 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001206 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001207 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001208
1209 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001210 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211}
1212
1213
1214Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1215 AccessorInfo* callback,
1216 String* name) {
1217 // ----------- S t a t e -------------
1218 // -- eax : value
1219 // -- ecx : name
1220 // -- esp[0] : return address
1221 // -- esp[4] : receiver
1222 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223 Label miss;
1224
1225 // Get the object from the stack.
1226 __ mov(ebx, Operand(esp, 1 * kPointerSize));
1227
1228 // Check that the object isn't a smi.
1229 __ test(ebx, Immediate(kSmiTagMask));
1230 __ j(zero, &miss, not_taken);
1231
1232 // Check that the map of the object hasn't changed.
1233 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
1234 Immediate(Handle<Map>(object->map())));
1235 __ j(not_equal, &miss, not_taken);
1236
1237 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001238 if (object->IsJSGlobalProxy()) {
1239 __ CheckAccessGlobalProxy(ebx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240 }
1241
1242 // Stub never generated for non-global objects that require access
1243 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001244 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245
1246 __ pop(ebx); // remove the return address
1247 __ push(Operand(esp, 0)); // receiver
1248 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback info
1249 __ push(ecx); // name
1250 __ push(eax); // value
1251 __ push(ebx); // restore return address
1252
mads.s.ager31e71382008-08-13 09:32:07 +00001253 // Do tail-call to the runtime system.
1254 ExternalReference store_callback_property =
1255 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
ager@chromium.orga1645e22009-09-09 19:27:10 +00001256 __ TailCallRuntime(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257
1258 // Handle store cache miss.
1259 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001260 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001262 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263
1264 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001265 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266}
1267
1268
1269Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1270 String* name) {
1271 // ----------- S t a t e -------------
1272 // -- eax : value
1273 // -- ecx : name
1274 // -- esp[0] : return address
1275 // -- esp[4] : receiver
1276 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 Label miss;
1278
1279 // Get the object from the stack.
1280 __ mov(ebx, Operand(esp, 1 * kPointerSize));
1281
1282 // Check that the object isn't a smi.
1283 __ test(ebx, Immediate(kSmiTagMask));
1284 __ j(zero, &miss, not_taken);
1285
1286 // Check that the map of the object hasn't changed.
1287 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
1288 Immediate(Handle<Map>(receiver->map())));
1289 __ j(not_equal, &miss, not_taken);
1290
1291 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001292 if (receiver->IsJSGlobalProxy()) {
1293 __ CheckAccessGlobalProxy(ebx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 }
1295
1296 // Stub never generated for non-global objects that require access
1297 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001298 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001299
1300 __ pop(ebx); // remove the return address
1301 __ push(Operand(esp, 0)); // receiver
1302 __ push(ecx); // name
1303 __ push(eax); // value
1304 __ push(ebx); // restore return address
1305
mads.s.ager31e71382008-08-13 09:32:07 +00001306 // Do tail-call to the runtime system.
1307 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001308 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
ager@chromium.orga1645e22009-09-09 19:27:10 +00001309 __ TailCallRuntime(store_ic_property, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310
1311 // Handle store cache miss.
1312 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001313 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001315 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316
1317 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001318 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319}
1320
1321
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001322Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1323 JSGlobalPropertyCell* cell,
1324 String* name) {
1325 // ----------- S t a t e -------------
1326 // -- eax : value
1327 // -- ecx : name
1328 // -- esp[0] : return address
1329 // -- esp[4] : receiver
1330 // -----------------------------------
1331 Label miss;
1332
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001333 // Check that the map of the global has not changed.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001334 __ mov(ebx, Operand(esp, kPointerSize));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001335 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
1336 Immediate(Handle<Map>(object->map())));
1337 __ j(not_equal, &miss, not_taken);
1338
1339 // Store the value in the cell.
1340 __ mov(ecx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
1341 __ mov(FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset), eax);
1342
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001343 // Return the value (register eax).
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001344 __ IncrementCounter(&Counters::named_store_global_inline, 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001345 __ ret(0);
1346
1347 // Handle store cache miss.
1348 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001349 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1);
1350 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1351 __ jmp(ic, RelocInfo::CODE_TARGET);
1352
1353 // Return the generated code.
1354 return GetCode(NORMAL, name);
1355}
1356
1357
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1359 int index,
1360 Map* transition,
1361 String* name) {
1362 // ----------- S t a t e -------------
1363 // -- eax : value
1364 // -- esp[0] : return address
1365 // -- esp[4] : key
1366 // -- esp[8] : receiver
1367 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001368 Label miss;
1369
1370 __ IncrementCounter(&Counters::keyed_store_field, 1);
1371
1372 // Get the name from the stack.
1373 __ mov(ecx, Operand(esp, 1 * kPointerSize));
1374 // Check that the name has not changed.
1375 __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
1376 __ j(not_equal, &miss, not_taken);
1377
1378 // Get the object from the stack.
1379 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1380
1381 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001382 GenerateStoreField(masm(),
1383 Builtins::KeyedStoreIC_ExtendStorage,
1384 object,
1385 index,
1386 transition,
1387 ebx, ecx, edx,
1388 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389
1390 // Handle store cache miss.
1391 __ bind(&miss);
1392 __ DecrementCounter(&Counters::keyed_store_field, 1);
1393 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001394 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001395
1396 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001397 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398}
1399
1400
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001401
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1403 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001404 int index,
1405 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406 // ----------- S t a t e -------------
1407 // -- ecx : name
1408 // -- esp[0] : return address
1409 // -- esp[4] : receiver
1410 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411 Label miss;
1412
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001413 __ mov(eax, Operand(esp, kPointerSize));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001414 GenerateLoadField(object, holder, eax, ebx, edx, index, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415 __ bind(&miss);
1416 GenerateLoadMiss(masm(), Code::LOAD_IC);
1417
1418 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001419 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420}
1421
1422
1423Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
1424 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001425 AccessorInfo* callback,
1426 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001427 // ----------- S t a t e -------------
1428 // -- ecx : name
1429 // -- esp[0] : return address
1430 // -- esp[4] : receiver
1431 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001432 Label miss;
1433
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001434 __ mov(eax, Operand(esp, kPointerSize));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001435 GenerateLoadCallback(object, holder, eax, ecx, ebx, edx,
1436 callback, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001437 __ bind(&miss);
1438 GenerateLoadMiss(masm(), Code::LOAD_IC);
1439
1440 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001441 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001442}
1443
1444
1445Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1446 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001447 Object* value,
1448 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449 // ----------- S t a t e -------------
1450 // -- ecx : name
1451 // -- esp[0] : return address
1452 // -- esp[4] : receiver
1453 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001454 Label miss;
1455
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001456 __ mov(eax, Operand(esp, kPointerSize));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001457 GenerateLoadConstant(object, holder, eax, ebx, edx, value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458 __ bind(&miss);
1459 GenerateLoadMiss(masm(), Code::LOAD_IC);
1460
1461 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001462 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001463}
1464
1465
1466Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1467 JSObject* holder,
1468 String* name) {
1469 // ----------- S t a t e -------------
1470 // -- ecx : name
1471 // -- esp[0] : return address
1472 // -- esp[4] : receiver
1473 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001474 Label miss;
1475
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001476 LookupResult lookup;
1477 LookupPostInterceptor(holder, name, &lookup);
1478
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001479 __ mov(eax, Operand(esp, kPointerSize));
ager@chromium.orge2902be2009-06-08 12:21:35 +00001480 // TODO(368): Compile in the whole chain: all the interceptors in
1481 // prototypes and ultimate answer.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001482 GenerateLoadInterceptor(receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001483 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001484 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001485 eax,
1486 ecx,
1487 edx,
1488 ebx,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001489 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001490 &miss);
1491
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001492 __ bind(&miss);
1493 GenerateLoadMiss(masm(), Code::LOAD_IC);
1494
1495 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001496 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497}
1498
1499
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001500Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1501 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001502 JSGlobalPropertyCell* cell,
1503 String* name,
1504 bool is_dont_delete) {
1505 // ----------- S t a t e -------------
1506 // -- ecx : name
1507 // -- esp[0] : return address
1508 // -- esp[4] : receiver
1509 // -----------------------------------
1510 Label miss;
1511
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001512 // Get the receiver from the stack.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001513 __ mov(eax, Operand(esp, kPointerSize));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001514
1515 // If the object is the holder then we know that it's a global
1516 // object which can only happen for contextual loads. In this case,
1517 // the receiver cannot be a smi.
1518 if (object != holder) {
1519 __ test(eax, Immediate(kSmiTagMask));
1520 __ j(zero, &miss, not_taken);
1521 }
1522
1523 // Check that the maps haven't changed.
1524 CheckPrototypes(object, eax, holder, ebx, edx, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001525
1526 // Get the value from the cell.
1527 __ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell)));
1528 __ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
1529
1530 // Check for deleted property if property can actually be deleted.
1531 if (!is_dont_delete) {
1532 __ cmp(eax, Factory::the_hole_value());
1533 __ j(equal, &miss, not_taken);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001534 } else if (FLAG_debug_code) {
1535 __ cmp(eax, Factory::the_hole_value());
1536 __ Check(not_equal, "DontDelete cells can't contain the hole");
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001537 }
1538
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001539 __ IncrementCounter(&Counters::named_load_global_inline, 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001540 __ ret(0);
1541
1542 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001543 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1);
1544 GenerateLoadMiss(masm(), Code::LOAD_IC);
1545
1546 // Return the generated code.
1547 return GetCode(NORMAL, name);
1548}
1549
1550
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001551Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1552 JSObject* receiver,
1553 JSObject* holder,
1554 int index) {
1555 // ----------- S t a t e -------------
1556 // -- esp[0] : return address
1557 // -- esp[4] : name
1558 // -- esp[8] : receiver
1559 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 Label miss;
1561
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001562 __ mov(eax, Operand(esp, kPointerSize));
1563 __ mov(ecx, Operand(esp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 __ IncrementCounter(&Counters::keyed_load_field, 1);
1565
1566 // Check that the name has not changed.
1567 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1568 __ j(not_equal, &miss, not_taken);
1569
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001570 GenerateLoadField(receiver, holder, ecx, ebx, edx, index, name, &miss);
1571
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572 __ bind(&miss);
1573 __ DecrementCounter(&Counters::keyed_load_field, 1);
1574 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1575
1576 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001577 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578}
1579
1580
1581Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1582 JSObject* receiver,
1583 JSObject* holder,
1584 AccessorInfo* callback) {
1585 // ----------- S t a t e -------------
1586 // -- esp[0] : return address
1587 // -- esp[4] : name
1588 // -- esp[8] : receiver
1589 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590 Label miss;
1591
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001592 __ mov(eax, Operand(esp, kPointerSize));
1593 __ mov(ecx, Operand(esp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594 __ IncrementCounter(&Counters::keyed_load_callback, 1);
1595
1596 // Check that the name has not changed.
1597 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1598 __ j(not_equal, &miss, not_taken);
1599
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001600 GenerateLoadCallback(receiver, holder, ecx, eax, ebx, edx,
1601 callback, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 __ bind(&miss);
1603 __ DecrementCounter(&Counters::keyed_load_callback, 1);
1604 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1605
1606 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001607 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001608}
1609
1610
1611Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1612 JSObject* receiver,
1613 JSObject* holder,
1614 Object* value) {
1615 // ----------- S t a t e -------------
1616 // -- esp[0] : return address
1617 // -- esp[4] : name
1618 // -- esp[8] : receiver
1619 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 Label miss;
1621
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001622 __ mov(eax, Operand(esp, kPointerSize));
1623 __ mov(ecx, Operand(esp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001624 __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
1625
1626 // Check that the name has not changed.
1627 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1628 __ j(not_equal, &miss, not_taken);
1629
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001630 GenerateLoadConstant(receiver, holder, ecx, ebx, edx,
1631 value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632 __ bind(&miss);
1633 __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
1634 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1635
1636 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001637 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638}
1639
1640
1641Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1642 JSObject* holder,
1643 String* name) {
1644 // ----------- S t a t e -------------
1645 // -- esp[0] : return address
1646 // -- esp[4] : name
1647 // -- esp[8] : receiver
1648 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001649 Label miss;
1650
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001651 __ mov(eax, Operand(esp, kPointerSize));
1652 __ mov(ecx, Operand(esp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001653 __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
1654
1655 // Check that the name has not changed.
1656 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1657 __ j(not_equal, &miss, not_taken);
1658
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001659 LookupResult lookup;
1660 LookupPostInterceptor(holder, name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001661 GenerateLoadInterceptor(receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001662 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001663 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001664 ecx,
1665 eax,
1666 edx,
1667 ebx,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001668 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001669 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001670 __ bind(&miss);
1671 __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
1672 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1673
1674 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001675 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001676}
1677
1678
1679
1680
1681Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1682 // ----------- S t a t e -------------
1683 // -- esp[0] : return address
1684 // -- esp[4] : name
1685 // -- esp[8] : receiver
1686 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001687 Label miss;
1688
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001689 __ mov(eax, Operand(esp, kPointerSize));
1690 __ mov(ecx, Operand(esp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001691 __ IncrementCounter(&Counters::keyed_load_array_length, 1);
1692
1693 // Check that the name has not changed.
1694 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1695 __ j(not_equal, &miss, not_taken);
1696
1697 GenerateLoadArrayLength(masm(), ecx, edx, &miss);
1698 __ bind(&miss);
1699 __ DecrementCounter(&Counters::keyed_load_array_length, 1);
1700 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1701
1702 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001703 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001704}
1705
1706
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001707Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001708 // ----------- S t a t e -------------
1709 // -- esp[0] : return address
1710 // -- esp[4] : name
1711 // -- esp[8] : receiver
1712 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001713 Label miss;
1714
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001715 __ mov(eax, Operand(esp, kPointerSize));
1716 __ mov(ecx, Operand(esp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001717 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1718
1719 // Check that the name has not changed.
1720 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1721 __ j(not_equal, &miss, not_taken);
1722
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001723 GenerateLoadStringLength(masm(), ecx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001724 __ bind(&miss);
1725 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1726 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1727
1728 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001729 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001730}
1731
1732
1733Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1734 // ----------- S t a t e -------------
1735 // -- esp[0] : return address
1736 // -- esp[4] : name
1737 // -- esp[8] : receiver
1738 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001739 Label miss;
1740
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001741 __ mov(eax, Operand(esp, kPointerSize));
1742 __ mov(ecx, Operand(esp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001743 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
1744
1745 // Check that the name has not changed.
1746 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1747 __ j(not_equal, &miss, not_taken);
1748
1749 GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss);
1750 __ bind(&miss);
1751 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
1752 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1753
1754 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001755 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001756}
1757
1758
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001759// Specialized stub for constructing objects from functions which only have only
1760// simple assignments of the form this.x = ...; in their body.
1761Object* ConstructStubCompiler::CompileConstructStub(
1762 SharedFunctionInfo* shared) {
1763 // ----------- S t a t e -------------
1764 // -- eax : argc
1765 // -- edi : constructor
1766 // -- esp[0] : return address
1767 // -- esp[4] : last argument
1768 // -----------------------------------
1769 Label generic_stub_call;
1770#ifdef ENABLE_DEBUGGER_SUPPORT
1771 // Check to see whether there are any break points in the function code. If
1772 // there are jump to the generic constructor stub which calls the actual
1773 // code for the function thereby hitting the break points.
1774 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1775 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset));
1776 __ cmp(ebx, Factory::undefined_value());
1777 __ j(not_equal, &generic_stub_call, not_taken);
1778#endif
1779
1780 // Load the initial map and verify that it is in fact a map.
1781 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1782 // Will both indicate a NULL and a Smi.
1783 __ test(ebx, Immediate(kSmiTagMask));
1784 __ j(zero, &generic_stub_call);
1785 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1786 __ j(not_equal, &generic_stub_call);
1787
1788#ifdef DEBUG
1789 // Cannot construct functions this way.
1790 // edi: constructor
1791 // ebx: initial map
1792 __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
1793 __ Assert(not_equal, "Function constructed by construct stub.");
1794#endif
1795
1796 // Now allocate the JSObject on the heap by moving the new space allocation
1797 // top forward.
1798 // edi: constructor
1799 // ebx: initial map
1800 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
1801 __ shl(ecx, kPointerSizeLog2);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001802 __ AllocateInNewSpace(ecx,
1803 edx,
1804 ecx,
1805 no_reg,
1806 &generic_stub_call,
1807 NO_ALLOCATION_FLAGS);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001808
1809 // Allocated the JSObject, now initialize the fields and add the heap tag.
1810 // ebx: initial map
1811 // edx: JSObject (untagged)
1812 __ mov(Operand(edx, JSObject::kMapOffset), ebx);
1813 __ mov(ebx, Factory::empty_fixed_array());
1814 __ mov(Operand(edx, JSObject::kPropertiesOffset), ebx);
1815 __ mov(Operand(edx, JSObject::kElementsOffset), ebx);
1816
1817 // Push the allocated object to the stack. This is the object that will be
1818 // returned (after it is tagged).
1819 __ push(edx);
1820
1821 // eax: argc
1822 // edx: JSObject (untagged)
1823 // Load the address of the first in-object property into edx.
1824 __ lea(edx, Operand(edx, JSObject::kHeaderSize));
1825 // Calculate the location of the first argument. The stack contains the
1826 // allocated object and the return address on top of the argc arguments.
1827 __ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize));
1828
1829 // Use edi for holding undefined which is used in several places below.
1830 __ mov(edi, Factory::undefined_value());
1831
1832 // eax: argc
1833 // ecx: first argument
1834 // edx: first in-object property of the JSObject
1835 // edi: undefined
1836 // Fill the initialized properties with a constant value or a passed argument
1837 // depending on the this.x = ...; assignment in the function.
1838 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
1839 if (shared->IsThisPropertyAssignmentArgument(i)) {
1840 Label not_passed;
1841 // Set the property to undefined.
1842 __ mov(Operand(edx, i * kPointerSize), edi);
1843 // Check if the argument assigned to the property is actually passed.
1844 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
1845 __ cmp(eax, arg_number);
1846 __ j(below_equal, &not_passed);
1847 // Argument passed - find it on the stack.
1848 __ mov(ebx, Operand(ecx, arg_number * -kPointerSize));
1849 __ mov(Operand(edx, i * kPointerSize), ebx);
1850 __ bind(&not_passed);
1851 } else {
1852 // Set the property to the constant value.
1853 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
1854 __ mov(Operand(edx, i * kPointerSize), Immediate(constant));
1855 }
1856 }
1857
1858 // Fill the unused in-object property fields with undefined.
1859 for (int i = shared->this_property_assignments_count();
1860 i < shared->CalculateInObjectProperties();
1861 i++) {
1862 __ mov(Operand(edx, i * kPointerSize), edi);
1863 }
1864
1865 // Move argc to ebx and retrieve and tag the JSObject to return.
1866 __ mov(ebx, eax);
1867 __ pop(eax);
1868 __ or_(Operand(eax), Immediate(kHeapObjectTag));
1869
1870 // Remove caller arguments and receiver from the stack and return.
1871 __ pop(ecx);
1872 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
1873 __ push(ecx);
1874 __ IncrementCounter(&Counters::constructed_objects, 1);
1875 __ IncrementCounter(&Counters::constructed_objects_stub, 1);
1876 __ ret(0);
1877
1878 // Jump to the generic stub in case the specialized code cannot handle the
1879 // construction.
1880 __ bind(&generic_stub_call);
1881 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
1882 Handle<Code> generic_construct_stub(code);
1883 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
1884
1885 // Return the generated code.
1886 return GetCode();
1887}
1888
1889
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890#undef __
1891
1892} } // namespace v8::internal