blob: 846b66760fde822d39acce63f2a1626c80d8134c [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
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000757bool StubCompiler::GenerateLoadCallback(JSObject* object,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000758 JSObject* holder,
759 Register receiver,
760 Register name_reg,
761 Register scratch1,
762 Register scratch2,
763 AccessorInfo* callback,
764 String* name,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000765 Label* miss,
766 Failure** failure) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000767 // Check that the receiver isn't a smi.
768 __ test(receiver, Immediate(kSmiTagMask));
769 __ j(zero, miss, not_taken);
770
771 // Check that the maps haven't changed.
772 Register reg =
773 CheckPrototypes(object, receiver, holder,
774 scratch1, scratch2, name, miss);
775
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000776 Handle<AccessorInfo> callback_handle(callback);
777
778 Register other = reg.is(scratch1) ? scratch2 : scratch1;
779 __ EnterInternalFrame();
780 __ PushHandleScope(other);
781 // Push the stack address where the list of arguments ends
782 __ mov(other, esp);
783 __ sub(Operand(other), Immediate(2 * kPointerSize));
784 __ push(other);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000785 __ push(receiver); // receiver
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000786 __ push(reg); // holder
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000787 __ mov(other, Immediate(callback_handle));
788 __ push(other);
789 __ push(FieldOperand(other, AccessorInfo::kDataOffset)); // data
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000790 __ push(name_reg); // name
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000791 // Save a pointer to where we pushed the arguments pointer.
792 // This will be passed as the const Arguments& to the C++ callback.
793 __ mov(eax, esp);
794 __ add(Operand(eax), Immediate(5 * kPointerSize));
795 __ mov(ebx, esp);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000796
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000797 // Do call through the api.
798 ASSERT_EQ(6, ApiGetterEntryStub::kStackSpace);
799 Address getter_address = v8::ToCData<Address>(callback->getter());
800 ApiFunction fun(getter_address);
801 ApiGetterEntryStub stub(callback_handle, &fun);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000802 // Calling the stub may try to allocate (if the code is not already
803 // generated). Do not allow the call to perform a garbage
804 // collection but instead return the allocation failure object.
805 Object* result = masm()->TryCallStub(&stub);
806 if (result->IsFailure()) {
807 *failure = Failure::cast(result);
808 return false;
809 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000810
811 // We need to avoid using eax since that now holds the result.
812 Register tmp = other.is(eax) ? reg : other;
813 __ PopHandleScope(eax, tmp);
814 __ LeaveInternalFrame();
815
816 __ ret(0);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000817 return true;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000818}
819
820
821void StubCompiler::GenerateLoadConstant(JSObject* object,
822 JSObject* holder,
823 Register receiver,
824 Register scratch1,
825 Register scratch2,
826 Object* value,
827 String* name,
828 Label* miss) {
829 // Check that the receiver isn't a smi.
830 __ test(receiver, Immediate(kSmiTagMask));
831 __ j(zero, miss, not_taken);
832
833 // Check that the maps haven't changed.
834 Register reg =
835 CheckPrototypes(object, receiver, holder,
836 scratch1, scratch2, name, miss);
837
838 // Return the constant value.
839 __ mov(eax, Handle<Object>(value));
840 __ ret(0);
841}
842
843
844void StubCompiler::GenerateLoadInterceptor(JSObject* object,
845 JSObject* holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000846 LookupResult* lookup,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000847 Register receiver,
848 Register name_reg,
849 Register scratch1,
850 Register scratch2,
851 String* name,
852 Label* miss) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000853 LoadInterceptorCompiler compiler(name_reg);
854 CompileLoadInterceptor(&compiler,
855 this,
856 masm(),
857 object,
858 holder,
859 name,
860 lookup,
861 receiver,
862 scratch1,
863 scratch2,
864 miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000865}
866
867
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868// TODO(1241006): Avoid having lazy compile stubs specialized by the
869// number of arguments. It is not needed anymore.
870Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000872 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873
874 // Push a copy of the function onto the stack.
875 __ push(edi);
876
877 __ push(edi); // function is also the parameter to the runtime call
878 __ CallRuntime(Runtime::kLazyCompile, 1);
879 __ pop(edi);
880
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000881 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000882 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000883
884 // Do a tail-call of the compiled function.
885 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
886 __ jmp(Operand(ecx));
887
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000888 return GetCodeWithFlags(flags, "LazyCompileStub");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889}
890
891
892Object* CallStubCompiler::CompileCallField(Object* object,
893 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000894 int index,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000895 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000896 // ----------- S t a t e -------------
897 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000898 Label miss;
899
900 // Get the receiver from the stack.
901 const int argc = arguments().immediate();
902 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
903
904 // Check that the receiver isn't a smi.
905 __ test(edx, Immediate(kSmiTagMask));
906 __ j(zero, &miss, not_taken);
907
908 // Do the right check and compute the holder register.
909 Register reg =
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000910 CheckPrototypes(JSObject::cast(object), edx, holder,
911 ebx, ecx, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000912
ager@chromium.org7c537e22008-10-16 08:43:32 +0000913 GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914
915 // Check that the function really is a function.
916 __ test(edi, Immediate(kSmiTagMask));
917 __ j(zero, &miss, not_taken);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000918 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000919 __ j(not_equal, &miss, not_taken);
920
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000921 // Patch the receiver on the stack with the global proxy if
922 // necessary.
923 if (object->IsGlobalObject()) {
924 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
925 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
926 }
927
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000928 // Invoke the function.
929 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
930
931 // Handle call cache miss.
932 __ bind(&miss);
933 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000934 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000935
936 // Return the generated code.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000937 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000938}
939
940
941Object* CallStubCompiler::CompileCallConstant(Object* object,
942 JSObject* holder,
943 JSFunction* function,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000944 String* name,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000945 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000946 // ----------- S t a t e -------------
947 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000948 Label miss;
949
950 // Get the receiver from the stack.
951 const int argc = arguments().immediate();
952 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
953
954 // Check that the receiver isn't a smi.
955 if (check != NUMBER_CHECK) {
956 __ test(edx, Immediate(kSmiTagMask));
957 __ j(zero, &miss, not_taken);
958 }
959
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000960 // Make sure that it's okay not to patch the on stack receiver
961 // unless we're doing a receiver map check.
962 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
963
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000964 switch (check) {
965 case RECEIVER_MAP_CHECK:
966 // Check that the maps haven't changed.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000967 CheckPrototypes(JSObject::cast(object), edx, holder,
968 ebx, ecx, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000969
970 // Patch the receiver on the stack with the global proxy if
971 // necessary.
972 if (object->IsGlobalObject()) {
973 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
974 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
975 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000976 break;
977
978 case STRING_CHECK:
979 // Check that the object is a two-byte string or a symbol.
980 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
981 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
982 __ cmp(ecx, FIRST_NONSTRING_TYPE);
983 __ j(above_equal, &miss, not_taken);
984 // Check that the maps starting from the prototype haven't changed.
985 GenerateLoadGlobalFunctionPrototype(masm(),
986 Context::STRING_FUNCTION_INDEX,
987 ecx);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000988 CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
989 ebx, edx, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000990 break;
991
992 case NUMBER_CHECK: {
993 Label fast;
994 // Check that the object is a smi or a heap number.
995 __ test(edx, Immediate(kSmiTagMask));
996 __ j(zero, &fast, taken);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000997 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 __ j(not_equal, &miss, not_taken);
999 __ bind(&fast);
1000 // Check that the maps starting from the prototype haven't changed.
1001 GenerateLoadGlobalFunctionPrototype(masm(),
1002 Context::NUMBER_FUNCTION_INDEX,
1003 ecx);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001004 CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
1005 ebx, edx, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006 break;
1007 }
1008
1009 case BOOLEAN_CHECK: {
1010 Label fast;
1011 // Check that the object is a boolean.
1012 __ cmp(edx, Factory::true_value());
1013 __ j(equal, &fast, taken);
1014 __ cmp(edx, Factory::false_value());
1015 __ j(not_equal, &miss, not_taken);
1016 __ bind(&fast);
1017 // Check that the maps starting from the prototype haven't changed.
1018 GenerateLoadGlobalFunctionPrototype(masm(),
1019 Context::BOOLEAN_FUNCTION_INDEX,
1020 ecx);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001021 CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
1022 ebx, edx, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023 break;
1024 }
1025
1026 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001027 CheckPrototypes(JSObject::cast(object), edx, holder,
1028 ebx, ecx, name, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001029 // Make sure object->HasFastElements().
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001030 // Get the elements array of the object.
1031 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
1032 // Check that the object is in fast mode (not dictionary).
1033 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001034 Immediate(Factory::fixed_array_map()));
1035 __ j(not_equal, &miss, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001036 break;
1037
1038 default:
1039 UNREACHABLE();
1040 }
1041
1042 // Get the function and setup the context.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001043 __ mov(edi, Immediate(Handle<JSFunction>(function)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001044 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1045
1046 // Jump to the cached code (tail call).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001047 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048 Handle<Code> code(function->code());
1049 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +00001050 __ InvokeCode(code, expected, arguments(),
1051 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052
1053 // Handle call cache miss.
1054 __ bind(&miss);
1055 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +00001056 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057
1058 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001059 String* function_name = NULL;
1060 if (function->shared()->name()->IsString()) {
1061 function_name = String::cast(function->shared()->name());
1062 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001063 return GetCode(CONSTANT_FUNCTION, function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064}
1065
1066
1067Object* CallStubCompiler::CompileCallInterceptor(Object* object,
1068 JSObject* holder,
1069 String* name) {
1070 // ----------- S t a t e -------------
1071 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072 Label miss;
1073
1074 // Get the number of arguments.
1075 const int argc = arguments().immediate();
1076
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001077 LookupResult lookup;
1078 LookupPostInterceptor(holder, name, &lookup);
1079
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080 // Get the receiver from the stack.
1081 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001082
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001083 CallInterceptorCompiler compiler(arguments());
1084 CompileLoadInterceptor(&compiler,
1085 this,
1086 masm(),
1087 JSObject::cast(object),
1088 holder,
1089 name,
1090 &lookup,
1091 edx,
1092 ebx,
1093 ecx,
1094 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001095
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001096 // Restore receiver.
1097 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098
1099 // Check that the function really is a function.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001100 __ test(eax, Immediate(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001101 __ j(zero, &miss, not_taken);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001102 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001103 __ j(not_equal, &miss, not_taken);
1104
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001105 // Patch the receiver on the stack with the global proxy if
1106 // necessary.
1107 if (object->IsGlobalObject()) {
1108 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1109 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1110 }
1111
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112 // Invoke the function.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001113 __ mov(edi, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001114 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
1115
1116 // Handle load cache miss.
1117 __ bind(&miss);
1118 Handle<Code> ic = ComputeCallMiss(argc);
ager@chromium.org236ad962008-09-25 09:45:57 +00001119 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120
1121 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001122 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001123}
1124
1125
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001126Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1127 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001128 JSGlobalPropertyCell* cell,
1129 JSFunction* function,
1130 String* name) {
1131 // ----------- S t a t e -------------
1132 // -----------------------------------
1133 Label miss;
1134
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001135 // Get the number of arguments.
1136 const int argc = arguments().immediate();
1137
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001138 // Get the receiver from the stack.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001139 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001140
1141 // If the object is the holder then we know that it's a global
1142 // object which can only happen for contextual calls. In this case,
1143 // the receiver cannot be a smi.
1144 if (object != holder) {
1145 __ test(edx, Immediate(kSmiTagMask));
1146 __ j(zero, &miss, not_taken);
1147 }
1148
1149 // Check that the maps haven't changed.
1150 CheckPrototypes(object, edx, holder, ebx, ecx, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001151
1152 // Get the value from the cell.
1153 __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
1154 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
1155
1156 // Check that the cell contains the same function.
1157 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function)));
1158 __ j(not_equal, &miss, not_taken);
1159
1160 // Patch the receiver on the stack with the global proxy.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001161 if (object->IsGlobalObject()) {
1162 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1163 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1164 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001165
1166 // Setup the context (function already in edi).
1167 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1168
1169 // Jump to the cached code (tail call).
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001170 __ IncrementCounter(&Counters::call_global_inline, 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001171 ASSERT(function->is_compiled());
1172 Handle<Code> code(function->code());
1173 ParameterCount expected(function->shared()->formal_parameter_count());
1174 __ InvokeCode(code, expected, arguments(),
1175 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1176
1177 // Handle call cache miss.
1178 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001179 __ IncrementCounter(&Counters::call_global_inline_miss, 1);
1180 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1181 __ jmp(ic, RelocInfo::CODE_TARGET);
1182
1183 // Return the generated code.
1184 return GetCode(NORMAL, name);
1185}
1186
1187
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1189 int index,
1190 Map* transition,
1191 String* name) {
1192 // ----------- S t a t e -------------
1193 // -- eax : value
1194 // -- ecx : name
1195 // -- esp[0] : return address
1196 // -- esp[4] : receiver
1197 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198 Label miss;
1199
1200 // Get the object from the stack.
1201 __ mov(ebx, Operand(esp, 1 * kPointerSize));
1202
1203 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001204 GenerateStoreField(masm(),
1205 Builtins::StoreIC_ExtendStorage,
1206 object,
1207 index,
1208 transition,
1209 ebx, ecx, edx,
1210 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211
1212 // Handle store cache miss.
1213 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001214 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001216 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001217
1218 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001219 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001220}
1221
1222
1223Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1224 AccessorInfo* callback,
1225 String* name) {
1226 // ----------- S t a t e -------------
1227 // -- eax : value
1228 // -- ecx : name
1229 // -- esp[0] : return address
1230 // -- esp[4] : receiver
1231 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232 Label miss;
1233
1234 // Get the object from the stack.
1235 __ mov(ebx, Operand(esp, 1 * kPointerSize));
1236
1237 // Check that the object isn't a smi.
1238 __ test(ebx, Immediate(kSmiTagMask));
1239 __ j(zero, &miss, not_taken);
1240
1241 // Check that the map of the object hasn't changed.
1242 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
1243 Immediate(Handle<Map>(object->map())));
1244 __ j(not_equal, &miss, not_taken);
1245
1246 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001247 if (object->IsJSGlobalProxy()) {
1248 __ CheckAccessGlobalProxy(ebx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249 }
1250
1251 // Stub never generated for non-global objects that require access
1252 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001253 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254
1255 __ pop(ebx); // remove the return address
1256 __ push(Operand(esp, 0)); // receiver
1257 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback info
1258 __ push(ecx); // name
1259 __ push(eax); // value
1260 __ push(ebx); // restore return address
1261
mads.s.ager31e71382008-08-13 09:32:07 +00001262 // Do tail-call to the runtime system.
1263 ExternalReference store_callback_property =
1264 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
ager@chromium.orga1645e22009-09-09 19:27:10 +00001265 __ TailCallRuntime(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266
1267 // Handle store cache miss.
1268 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001269 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001271 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001272
1273 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001274 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001275}
1276
1277
1278Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1279 String* name) {
1280 // ----------- S t a t e -------------
1281 // -- eax : value
1282 // -- ecx : name
1283 // -- esp[0] : return address
1284 // -- esp[4] : receiver
1285 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 Label miss;
1287
1288 // Get the object from the stack.
1289 __ mov(ebx, Operand(esp, 1 * kPointerSize));
1290
1291 // Check that the object isn't a smi.
1292 __ test(ebx, Immediate(kSmiTagMask));
1293 __ j(zero, &miss, not_taken);
1294
1295 // Check that the map of the object hasn't changed.
1296 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
1297 Immediate(Handle<Map>(receiver->map())));
1298 __ j(not_equal, &miss, not_taken);
1299
1300 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001301 if (receiver->IsJSGlobalProxy()) {
1302 __ CheckAccessGlobalProxy(ebx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303 }
1304
1305 // Stub never generated for non-global objects that require access
1306 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001307 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001308
1309 __ pop(ebx); // remove the return address
1310 __ push(Operand(esp, 0)); // receiver
1311 __ push(ecx); // name
1312 __ push(eax); // value
1313 __ push(ebx); // restore return address
1314
mads.s.ager31e71382008-08-13 09:32:07 +00001315 // Do tail-call to the runtime system.
1316 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
ager@chromium.orga1645e22009-09-09 19:27:10 +00001318 __ TailCallRuntime(store_ic_property, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
1320 // Handle store cache miss.
1321 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001322 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001324 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325
1326 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001327 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001328}
1329
1330
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001331Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1332 JSGlobalPropertyCell* cell,
1333 String* name) {
1334 // ----------- S t a t e -------------
1335 // -- eax : value
1336 // -- ecx : name
1337 // -- esp[0] : return address
1338 // -- esp[4] : receiver
1339 // -----------------------------------
1340 Label miss;
1341
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001342 // Check that the map of the global has not changed.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001343 __ mov(ebx, Operand(esp, kPointerSize));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001344 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
1345 Immediate(Handle<Map>(object->map())));
1346 __ j(not_equal, &miss, not_taken);
1347
1348 // Store the value in the cell.
1349 __ mov(ecx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
1350 __ mov(FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset), eax);
1351
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001352 // Return the value (register eax).
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001353 __ IncrementCounter(&Counters::named_store_global_inline, 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001354 __ ret(0);
1355
1356 // Handle store cache miss.
1357 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001358 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1);
1359 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1360 __ jmp(ic, RelocInfo::CODE_TARGET);
1361
1362 // Return the generated code.
1363 return GetCode(NORMAL, name);
1364}
1365
1366
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001367Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1368 int index,
1369 Map* transition,
1370 String* name) {
1371 // ----------- S t a t e -------------
1372 // -- eax : value
1373 // -- esp[0] : return address
1374 // -- esp[4] : key
1375 // -- esp[8] : receiver
1376 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001377 Label miss;
1378
1379 __ IncrementCounter(&Counters::keyed_store_field, 1);
1380
1381 // Get the name from the stack.
1382 __ mov(ecx, Operand(esp, 1 * kPointerSize));
1383 // Check that the name has not changed.
1384 __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
1385 __ j(not_equal, &miss, not_taken);
1386
1387 // Get the object from the stack.
1388 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1389
1390 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001391 GenerateStoreField(masm(),
1392 Builtins::KeyedStoreIC_ExtendStorage,
1393 object,
1394 index,
1395 transition,
1396 ebx, ecx, edx,
1397 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398
1399 // Handle store cache miss.
1400 __ bind(&miss);
1401 __ DecrementCounter(&Counters::keyed_store_field, 1);
1402 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001403 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404
1405 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001406 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407}
1408
1409
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001410
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1412 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001413 int index,
1414 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415 // ----------- S t a t e -------------
1416 // -- ecx : name
1417 // -- esp[0] : return address
1418 // -- esp[4] : receiver
1419 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420 Label miss;
1421
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001422 __ mov(eax, Operand(esp, kPointerSize));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001423 GenerateLoadField(object, holder, eax, ebx, edx, index, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424 __ bind(&miss);
1425 GenerateLoadMiss(masm(), Code::LOAD_IC);
1426
1427 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001428 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001429}
1430
1431
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001432Object* LoadStubCompiler::CompileLoadCallback(String* name,
1433 JSObject* object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434 JSObject* holder,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001435 AccessorInfo* callback) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436 // ----------- S t a t e -------------
1437 // -- ecx : name
1438 // -- esp[0] : return address
1439 // -- esp[4] : receiver
1440 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441 Label miss;
1442
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001443 __ mov(eax, Operand(esp, kPointerSize));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001444 Failure* failure = Failure::InternalError();
1445 bool success = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx,
1446 callback, name, &miss, &failure);
1447 if (!success) return failure;
1448
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449 __ bind(&miss);
1450 GenerateLoadMiss(masm(), Code::LOAD_IC);
1451
1452 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001453 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001454}
1455
1456
1457Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1458 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001459 Object* value,
1460 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001461 // ----------- S t a t e -------------
1462 // -- ecx : name
1463 // -- esp[0] : return address
1464 // -- esp[4] : receiver
1465 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466 Label miss;
1467
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001468 __ mov(eax, Operand(esp, kPointerSize));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001469 GenerateLoadConstant(object, holder, eax, ebx, edx, value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470 __ bind(&miss);
1471 GenerateLoadMiss(masm(), Code::LOAD_IC);
1472
1473 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001474 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475}
1476
1477
1478Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1479 JSObject* holder,
1480 String* name) {
1481 // ----------- S t a t e -------------
1482 // -- ecx : name
1483 // -- esp[0] : return address
1484 // -- esp[4] : receiver
1485 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001486 Label miss;
1487
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001488 LookupResult lookup;
1489 LookupPostInterceptor(holder, name, &lookup);
1490
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001491 __ mov(eax, Operand(esp, kPointerSize));
ager@chromium.orge2902be2009-06-08 12:21:35 +00001492 // TODO(368): Compile in the whole chain: all the interceptors in
1493 // prototypes and ultimate answer.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001494 GenerateLoadInterceptor(receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001495 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001496 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001497 eax,
1498 ecx,
1499 edx,
1500 ebx,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001501 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001502 &miss);
1503
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504 __ bind(&miss);
1505 GenerateLoadMiss(masm(), Code::LOAD_IC);
1506
1507 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001508 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509}
1510
1511
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001512Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1513 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001514 JSGlobalPropertyCell* cell,
1515 String* name,
1516 bool is_dont_delete) {
1517 // ----------- S t a t e -------------
1518 // -- ecx : name
1519 // -- esp[0] : return address
1520 // -- esp[4] : receiver
1521 // -----------------------------------
1522 Label miss;
1523
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001524 // Get the receiver from the stack.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001525 __ mov(eax, Operand(esp, kPointerSize));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001526
1527 // If the object is the holder then we know that it's a global
1528 // object which can only happen for contextual loads. In this case,
1529 // the receiver cannot be a smi.
1530 if (object != holder) {
1531 __ test(eax, Immediate(kSmiTagMask));
1532 __ j(zero, &miss, not_taken);
1533 }
1534
1535 // Check that the maps haven't changed.
1536 CheckPrototypes(object, eax, holder, ebx, edx, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001537
1538 // Get the value from the cell.
1539 __ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell)));
1540 __ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
1541
1542 // Check for deleted property if property can actually be deleted.
1543 if (!is_dont_delete) {
1544 __ cmp(eax, Factory::the_hole_value());
1545 __ j(equal, &miss, not_taken);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001546 } else if (FLAG_debug_code) {
1547 __ cmp(eax, Factory::the_hole_value());
1548 __ Check(not_equal, "DontDelete cells can't contain the hole");
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001549 }
1550
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001551 __ IncrementCounter(&Counters::named_load_global_inline, 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001552 __ ret(0);
1553
1554 __ bind(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001555 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1);
1556 GenerateLoadMiss(masm(), Code::LOAD_IC);
1557
1558 // Return the generated code.
1559 return GetCode(NORMAL, name);
1560}
1561
1562
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1564 JSObject* receiver,
1565 JSObject* holder,
1566 int index) {
1567 // ----------- S t a t e -------------
1568 // -- esp[0] : return address
1569 // -- esp[4] : name
1570 // -- esp[8] : receiver
1571 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572 Label miss;
1573
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001574 __ mov(eax, Operand(esp, kPointerSize));
1575 __ mov(ecx, Operand(esp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576 __ IncrementCounter(&Counters::keyed_load_field, 1);
1577
1578 // Check that the name has not changed.
1579 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1580 __ j(not_equal, &miss, not_taken);
1581
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001582 GenerateLoadField(receiver, holder, ecx, ebx, edx, index, name, &miss);
1583
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001584 __ bind(&miss);
1585 __ DecrementCounter(&Counters::keyed_load_field, 1);
1586 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1587
1588 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001589 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590}
1591
1592
1593Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1594 JSObject* receiver,
1595 JSObject* holder,
1596 AccessorInfo* callback) {
1597 // ----------- S t a t e -------------
1598 // -- esp[0] : return address
1599 // -- esp[4] : name
1600 // -- esp[8] : receiver
1601 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 Label miss;
1603
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001604 __ mov(eax, Operand(esp, kPointerSize));
1605 __ mov(ecx, Operand(esp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001606 __ IncrementCounter(&Counters::keyed_load_callback, 1);
1607
1608 // Check that the name has not changed.
1609 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1610 __ j(not_equal, &miss, not_taken);
1611
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001612 Failure* failure = Failure::InternalError();
1613 bool success = GenerateLoadCallback(receiver, holder, ecx, eax, ebx, edx,
1614 callback, name, &miss, &failure);
1615 if (!success) return failure;
1616
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617 __ bind(&miss);
1618 __ DecrementCounter(&Counters::keyed_load_callback, 1);
1619 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1620
1621 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001622 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001623}
1624
1625
1626Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1627 JSObject* receiver,
1628 JSObject* holder,
1629 Object* value) {
1630 // ----------- S t a t e -------------
1631 // -- esp[0] : return address
1632 // -- esp[4] : name
1633 // -- esp[8] : receiver
1634 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635 Label miss;
1636
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001637 __ mov(eax, Operand(esp, kPointerSize));
1638 __ mov(ecx, Operand(esp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001639 __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
1640
1641 // Check that the name has not changed.
1642 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1643 __ j(not_equal, &miss, not_taken);
1644
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001645 GenerateLoadConstant(receiver, holder, ecx, ebx, edx,
1646 value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001647 __ bind(&miss);
1648 __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
1649 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1650
1651 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001652 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001653}
1654
1655
1656Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1657 JSObject* holder,
1658 String* name) {
1659 // ----------- S t a t e -------------
1660 // -- esp[0] : return address
1661 // -- esp[4] : name
1662 // -- esp[8] : receiver
1663 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001664 Label miss;
1665
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001666 __ mov(eax, Operand(esp, kPointerSize));
1667 __ mov(ecx, Operand(esp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001668 __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
1669
1670 // Check that the name has not changed.
1671 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1672 __ j(not_equal, &miss, not_taken);
1673
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001674 LookupResult lookup;
1675 LookupPostInterceptor(holder, name, &lookup);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001676 GenerateLoadInterceptor(receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001677 holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001678 &lookup,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001679 ecx,
1680 eax,
1681 edx,
1682 ebx,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001683 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001684 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001685 __ bind(&miss);
1686 __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
1687 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1688
1689 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001690 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001691}
1692
1693
1694
1695
1696Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1697 // ----------- S t a t e -------------
1698 // -- esp[0] : return address
1699 // -- esp[4] : name
1700 // -- esp[8] : receiver
1701 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702 Label miss;
1703
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001704 __ mov(eax, Operand(esp, kPointerSize));
1705 __ mov(ecx, Operand(esp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001706 __ IncrementCounter(&Counters::keyed_load_array_length, 1);
1707
1708 // Check that the name has not changed.
1709 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1710 __ j(not_equal, &miss, not_taken);
1711
1712 GenerateLoadArrayLength(masm(), ecx, edx, &miss);
1713 __ bind(&miss);
1714 __ DecrementCounter(&Counters::keyed_load_array_length, 1);
1715 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1716
1717 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001718 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719}
1720
1721
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001722Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001723 // ----------- S t a t e -------------
1724 // -- esp[0] : return address
1725 // -- esp[4] : name
1726 // -- esp[8] : receiver
1727 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001728 Label miss;
1729
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001730 __ mov(eax, Operand(esp, kPointerSize));
1731 __ mov(ecx, Operand(esp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001732 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1733
1734 // Check that the name has not changed.
1735 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1736 __ j(not_equal, &miss, not_taken);
1737
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001738 GenerateLoadStringLength(masm(), ecx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001739 __ bind(&miss);
1740 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1741 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1742
1743 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001744 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001745}
1746
1747
1748Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1749 // ----------- S t a t e -------------
1750 // -- esp[0] : return address
1751 // -- esp[4] : name
1752 // -- esp[8] : receiver
1753 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001754 Label miss;
1755
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001756 __ mov(eax, Operand(esp, kPointerSize));
1757 __ mov(ecx, Operand(esp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001758 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
1759
1760 // Check that the name has not changed.
1761 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1762 __ j(not_equal, &miss, not_taken);
1763
1764 GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss);
1765 __ bind(&miss);
1766 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
1767 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1768
1769 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001770 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001771}
1772
1773
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001774// Specialized stub for constructing objects from functions which only have only
1775// simple assignments of the form this.x = ...; in their body.
1776Object* ConstructStubCompiler::CompileConstructStub(
1777 SharedFunctionInfo* shared) {
1778 // ----------- S t a t e -------------
1779 // -- eax : argc
1780 // -- edi : constructor
1781 // -- esp[0] : return address
1782 // -- esp[4] : last argument
1783 // -----------------------------------
1784 Label generic_stub_call;
1785#ifdef ENABLE_DEBUGGER_SUPPORT
1786 // Check to see whether there are any break points in the function code. If
1787 // there are jump to the generic constructor stub which calls the actual
1788 // code for the function thereby hitting the break points.
1789 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1790 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset));
1791 __ cmp(ebx, Factory::undefined_value());
1792 __ j(not_equal, &generic_stub_call, not_taken);
1793#endif
1794
1795 // Load the initial map and verify that it is in fact a map.
1796 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1797 // Will both indicate a NULL and a Smi.
1798 __ test(ebx, Immediate(kSmiTagMask));
1799 __ j(zero, &generic_stub_call);
1800 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1801 __ j(not_equal, &generic_stub_call);
1802
1803#ifdef DEBUG
1804 // Cannot construct functions this way.
1805 // edi: constructor
1806 // ebx: initial map
1807 __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
1808 __ Assert(not_equal, "Function constructed by construct stub.");
1809#endif
1810
1811 // Now allocate the JSObject on the heap by moving the new space allocation
1812 // top forward.
1813 // edi: constructor
1814 // ebx: initial map
1815 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
1816 __ shl(ecx, kPointerSizeLog2);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001817 __ AllocateInNewSpace(ecx,
1818 edx,
1819 ecx,
1820 no_reg,
1821 &generic_stub_call,
1822 NO_ALLOCATION_FLAGS);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001823
1824 // Allocated the JSObject, now initialize the fields and add the heap tag.
1825 // ebx: initial map
1826 // edx: JSObject (untagged)
1827 __ mov(Operand(edx, JSObject::kMapOffset), ebx);
1828 __ mov(ebx, Factory::empty_fixed_array());
1829 __ mov(Operand(edx, JSObject::kPropertiesOffset), ebx);
1830 __ mov(Operand(edx, JSObject::kElementsOffset), ebx);
1831
1832 // Push the allocated object to the stack. This is the object that will be
1833 // returned (after it is tagged).
1834 __ push(edx);
1835
1836 // eax: argc
1837 // edx: JSObject (untagged)
1838 // Load the address of the first in-object property into edx.
1839 __ lea(edx, Operand(edx, JSObject::kHeaderSize));
1840 // Calculate the location of the first argument. The stack contains the
1841 // allocated object and the return address on top of the argc arguments.
1842 __ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize));
1843
1844 // Use edi for holding undefined which is used in several places below.
1845 __ mov(edi, Factory::undefined_value());
1846
1847 // eax: argc
1848 // ecx: first argument
1849 // edx: first in-object property of the JSObject
1850 // edi: undefined
1851 // Fill the initialized properties with a constant value or a passed argument
1852 // depending on the this.x = ...; assignment in the function.
1853 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
1854 if (shared->IsThisPropertyAssignmentArgument(i)) {
1855 Label not_passed;
1856 // Set the property to undefined.
1857 __ mov(Operand(edx, i * kPointerSize), edi);
1858 // Check if the argument assigned to the property is actually passed.
1859 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
1860 __ cmp(eax, arg_number);
1861 __ j(below_equal, &not_passed);
1862 // Argument passed - find it on the stack.
1863 __ mov(ebx, Operand(ecx, arg_number * -kPointerSize));
1864 __ mov(Operand(edx, i * kPointerSize), ebx);
1865 __ bind(&not_passed);
1866 } else {
1867 // Set the property to the constant value.
1868 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
1869 __ mov(Operand(edx, i * kPointerSize), Immediate(constant));
1870 }
1871 }
1872
1873 // Fill the unused in-object property fields with undefined.
1874 for (int i = shared->this_property_assignments_count();
1875 i < shared->CalculateInObjectProperties();
1876 i++) {
1877 __ mov(Operand(edx, i * kPointerSize), edi);
1878 }
1879
1880 // Move argc to ebx and retrieve and tag the JSObject to return.
1881 __ mov(ebx, eax);
1882 __ pop(eax);
1883 __ or_(Operand(eax), Immediate(kHeapObjectTag));
1884
1885 // Remove caller arguments and receiver from the stack and return.
1886 __ pop(ecx);
1887 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
1888 __ push(ecx);
1889 __ IncrementCounter(&Counters::constructed_objects, 1);
1890 __ IncrementCounter(&Counters::constructed_objects_stub, 1);
1891 __ ret(0);
1892
1893 // Jump to the generic stub in case the specialized code cannot handle the
1894 // construction.
1895 __ bind(&generic_stub_call);
1896 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
1897 Handle<Code> generic_construct_stub(code);
1898 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
1899
1900 // Return the generated code.
1901 return GetCode();
1902}
1903
1904
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001905#undef __
1906
1907} } // namespace v8::internal