blob: e10dc61b2ca2512515a0b65ee534bc0d03267289 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
2// 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 "api.h"
31#include "arguments.h"
32#include "ic-inl.h"
33#include "stub-cache.h"
34
35namespace v8 {
36namespace internal {
37
38// -----------------------------------------------------------------------
39// StubCache implementation.
40
41
42StubCache::Entry StubCache::primary_[StubCache::kPrimaryTableSize];
43StubCache::Entry StubCache::secondary_[StubCache::kSecondaryTableSize];
44
45void StubCache::Initialize(bool create_heap_objects) {
46 ASSERT(IsPowerOf2(kPrimaryTableSize));
47 ASSERT(IsPowerOf2(kSecondaryTableSize));
48 if (create_heap_objects) {
49 HandleScope scope;
50 Clear();
51 }
52}
53
54
55Code* StubCache::Set(String* name, Map* map, Code* code) {
56 // Get the flags from the code.
57 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
58
59 // Validate that the name does not move on scavenge, and that we
60 // can use identity checks instead of string equality checks.
61 ASSERT(!Heap::InNewSpace(name));
62 ASSERT(name->IsSymbol());
63
64 // The state bits are not important to the hash function because
65 // the stub cache only contains monomorphic stubs. Make sure that
66 // the bits are the least significant so they will be the ones
67 // masked out.
68 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
69 ASSERT(Code::kFlagsICStateShift == 0);
70
71 // Make sure that the code type is not included in the hash.
72 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
73
74 // Compute the primary entry.
75 int primary_offset = PrimaryOffset(name, flags, map);
76 Entry* primary = entry(primary_, primary_offset);
77 Code* hit = primary->value;
78
79 // If the primary entry has useful data in it, we retire it to the
80 // secondary cache before overwriting it.
81 if (hit != Builtins::builtin(Builtins::Illegal)) {
82 Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
83 int secondary_offset =
84 SecondaryOffset(primary->key, primary_flags, primary_offset);
85 Entry* secondary = entry(secondary_, secondary_offset);
86 *secondary = *primary;
87 }
88
89 // Update primary cache.
90 primary->key = name;
91 primary->value = code;
92 return code;
93}
94
95
96Object* StubCache::ComputeLoadField(String* name,
97 JSObject* receiver,
98 JSObject* holder,
99 int field_index) {
100 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
101 Object* code = receiver->map()->FindInCodeCache(name, flags);
102 if (code->IsUndefined()) {
103 LoadStubCompiler compiler;
104 code = compiler.CompileLoadField(receiver, holder, field_index, name);
105 if (code->IsFailure()) return code;
106 LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
107 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
108 if (result->IsFailure()) return code;
109 }
110 return Set(name, receiver->map(), Code::cast(code));
111}
112
113
114Object* StubCache::ComputeLoadCallback(String* name,
115 JSObject* receiver,
116 JSObject* holder,
117 AccessorInfo* callback) {
118 ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
119 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
120 Object* code = receiver->map()->FindInCodeCache(name, flags);
121 if (code->IsUndefined()) {
122 LoadStubCompiler compiler;
123 code = compiler.CompileLoadCallback(receiver, holder, callback, name);
124 if (code->IsFailure()) return code;
125 LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
126 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
127 if (result->IsFailure()) return code;
128 }
129 return Set(name, receiver->map(), Code::cast(code));
130}
131
132
133Object* StubCache::ComputeLoadConstant(String* name,
134 JSObject* receiver,
135 JSObject* holder,
136 Object* value) {
137 Code::Flags flags =
138 Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
139 Object* code = receiver->map()->FindInCodeCache(name, flags);
140 if (code->IsUndefined()) {
141 LoadStubCompiler compiler;
142 code = compiler.CompileLoadConstant(receiver, holder, value, name);
143 if (code->IsFailure()) return code;
144 LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
145 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
146 if (result->IsFailure()) return code;
147 }
148 return Set(name, receiver->map(), Code::cast(code));
149}
150
151
152Object* StubCache::ComputeLoadInterceptor(String* name,
153 JSObject* receiver,
154 JSObject* holder) {
155 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
156 Object* code = receiver->map()->FindInCodeCache(name, flags);
157 if (code->IsUndefined()) {
158 LoadStubCompiler compiler;
159 code = compiler.CompileLoadInterceptor(receiver, holder, name);
160 if (code->IsFailure()) return code;
161 LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
162 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
163 if (result->IsFailure()) return code;
164 }
165 return Set(name, receiver->map(), Code::cast(code));
166}
167
168
169Object* StubCache::ComputeLoadNormal(String* name, JSObject* receiver) {
170 Code* code = Builtins::builtin(Builtins::LoadIC_Normal);
171 return Set(name, receiver->map(), code);
172}
173
174
175Object* StubCache::ComputeLoadGlobal(String* name,
176 JSObject* receiver,
177 GlobalObject* holder,
178 JSGlobalPropertyCell* cell,
179 bool is_dont_delete) {
180 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
181 Object* code = receiver->map()->FindInCodeCache(name, flags);
182 if (code->IsUndefined()) {
183 LoadStubCompiler compiler;
184 code = compiler.CompileLoadGlobal(receiver,
185 holder,
186 cell,
187 name,
188 is_dont_delete);
189 if (code->IsFailure()) return code;
190 LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
191 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
192 if (result->IsFailure()) return code;
193 }
194 return Set(name, receiver->map(), Code::cast(code));
195}
196
197
198Object* StubCache::ComputeKeyedLoadField(String* name,
199 JSObject* receiver,
200 JSObject* holder,
201 int field_index) {
202 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
203 Object* code = receiver->map()->FindInCodeCache(name, flags);
204 if (code->IsUndefined()) {
205 KeyedLoadStubCompiler compiler;
206 code = compiler.CompileLoadField(name, receiver, holder, field_index);
207 if (code->IsFailure()) return code;
208 LOG(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
209 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
210 if (result->IsFailure()) return result;
211 }
212 return code;
213}
214
215
216Object* StubCache::ComputeKeyedLoadConstant(String* name,
217 JSObject* receiver,
218 JSObject* holder,
219 Object* value) {
220 Code::Flags flags =
221 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
222 Object* code = receiver->map()->FindInCodeCache(name, flags);
223 if (code->IsUndefined()) {
224 KeyedLoadStubCompiler compiler;
225 code = compiler.CompileLoadConstant(name, receiver, holder, value);
226 if (code->IsFailure()) return code;
227 LOG(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
228 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
229 if (result->IsFailure()) return result;
230 }
231 return code;
232}
233
234
235Object* StubCache::ComputeKeyedLoadInterceptor(String* name,
236 JSObject* receiver,
237 JSObject* holder) {
238 Code::Flags flags =
239 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
240 Object* code = receiver->map()->FindInCodeCache(name, flags);
241 if (code->IsUndefined()) {
242 KeyedLoadStubCompiler compiler;
243 code = compiler.CompileLoadInterceptor(receiver, holder, name);
244 if (code->IsFailure()) return code;
245 LOG(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
246 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
247 if (result->IsFailure()) return result;
248 }
249 return code;
250}
251
252
253Object* StubCache::ComputeKeyedLoadCallback(String* name,
254 JSObject* receiver,
255 JSObject* holder,
256 AccessorInfo* callback) {
257 Code::Flags flags =
258 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
259 Object* code = receiver->map()->FindInCodeCache(name, flags);
260 if (code->IsUndefined()) {
261 KeyedLoadStubCompiler compiler;
262 code = compiler.CompileLoadCallback(name, receiver, holder, callback);
263 if (code->IsFailure()) return code;
264 LOG(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
265 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
266 if (result->IsFailure()) return result;
267 }
268 return code;
269}
270
271
272
273Object* StubCache::ComputeKeyedLoadArrayLength(String* name,
274 JSArray* receiver) {
275 Code::Flags flags =
276 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
277 Object* code = receiver->map()->FindInCodeCache(name, flags);
278 if (code->IsUndefined()) {
279 KeyedLoadStubCompiler compiler;
280 code = compiler.CompileLoadArrayLength(name);
281 if (code->IsFailure()) return code;
282 LOG(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
283 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
284 if (result->IsFailure()) return result;
285 }
286 return code;
287}
288
289
290Object* StubCache::ComputeKeyedLoadStringLength(String* name,
291 String* receiver) {
292 Code::Flags flags =
293 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
294 Object* code = receiver->map()->FindInCodeCache(name, flags);
295 if (code->IsUndefined()) {
296 KeyedLoadStubCompiler compiler;
297 code = compiler.CompileLoadStringLength(name);
298 if (code->IsFailure()) return code;
299 LOG(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
300 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
301 if (result->IsFailure()) return result;
302 }
303 return code;
304}
305
306
307Object* StubCache::ComputeKeyedLoadFunctionPrototype(String* name,
308 JSFunction* receiver) {
309 Code::Flags flags =
310 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
311 Object* code = receiver->map()->FindInCodeCache(name, flags);
312 if (code->IsUndefined()) {
313 KeyedLoadStubCompiler compiler;
314 code = compiler.CompileLoadFunctionPrototype(name);
315 if (code->IsFailure()) return code;
316 LOG(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
317 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
318 if (result->IsFailure()) return result;
319 }
320 return code;
321}
322
323
324Object* StubCache::ComputeStoreField(String* name,
325 JSObject* receiver,
326 int field_index,
327 Map* transition) {
328 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
329 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
330 Object* code = receiver->map()->FindInCodeCache(name, flags);
331 if (code->IsUndefined()) {
332 StoreStubCompiler compiler;
333 code = compiler.CompileStoreField(receiver, field_index, transition, name);
334 if (code->IsFailure()) return code;
335 LOG(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
336 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
337 if (result->IsFailure()) return result;
338 }
339 return Set(name, receiver->map(), Code::cast(code));
340}
341
342
343Object* StubCache::ComputeStoreGlobal(String* name,
344 GlobalObject* receiver,
345 JSGlobalPropertyCell* cell) {
346 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL);
347 Object* code = receiver->map()->FindInCodeCache(name, flags);
348 if (code->IsUndefined()) {
349 StoreStubCompiler compiler;
350 code = compiler.CompileStoreGlobal(receiver, cell, name);
351 if (code->IsFailure()) return code;
352 LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
353 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
354 if (result->IsFailure()) return code;
355 }
356 return Set(name, receiver->map(), Code::cast(code));
357}
358
359
360Object* StubCache::ComputeStoreCallback(String* name,
361 JSObject* receiver,
362 AccessorInfo* callback) {
363 ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
364 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, CALLBACKS);
365 Object* code = receiver->map()->FindInCodeCache(name, flags);
366 if (code->IsUndefined()) {
367 StoreStubCompiler compiler;
368 code = compiler.CompileStoreCallback(receiver, callback, name);
369 if (code->IsFailure()) return code;
370 LOG(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
371 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
372 if (result->IsFailure()) return result;
373 }
374 return Set(name, receiver->map(), Code::cast(code));
375}
376
377
378Object* StubCache::ComputeStoreInterceptor(String* name,
379 JSObject* receiver) {
380 Code::Flags flags =
381 Code::ComputeMonomorphicFlags(Code::STORE_IC, INTERCEPTOR);
382 Object* code = receiver->map()->FindInCodeCache(name, flags);
383 if (code->IsUndefined()) {
384 StoreStubCompiler compiler;
385 code = compiler.CompileStoreInterceptor(receiver, name);
386 if (code->IsFailure()) return code;
387 LOG(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
388 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
389 if (result->IsFailure()) return result;
390 }
391 return Set(name, receiver->map(), Code::cast(code));
392}
393
394
395Object* StubCache::ComputeKeyedStoreField(String* name, JSObject* receiver,
396 int field_index, Map* transition) {
397 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
398 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
399 Object* code = receiver->map()->FindInCodeCache(name, flags);
400 if (code->IsUndefined()) {
401 KeyedStoreStubCompiler compiler;
402 code = compiler.CompileStoreField(receiver, field_index, transition, name);
403 if (code->IsFailure()) return code;
404 LOG(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), name));
405 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
406 if (result->IsFailure()) return result;
407 }
408 return code;
409}
410
411
412Object* StubCache::ComputeCallConstant(int argc,
413 InLoopFlag in_loop,
414 String* name,
415 Object* object,
416 JSObject* holder,
417 JSFunction* function) {
418 // Compute the check type and the map.
419 Map* map = IC::GetCodeCacheMapForObject(object);
420
421 // Compute check type based on receiver/holder.
422 StubCompiler::CheckType check = StubCompiler::RECEIVER_MAP_CHECK;
423 if (object->IsString()) {
424 check = StubCompiler::STRING_CHECK;
425 } else if (object->IsNumber()) {
426 check = StubCompiler::NUMBER_CHECK;
427 } else if (object->IsBoolean()) {
428 check = StubCompiler::BOOLEAN_CHECK;
429 }
430
431 Code::Flags flags =
432 Code::ComputeMonomorphicFlags(Code::CALL_IC,
433 CONSTANT_FUNCTION,
434 in_loop,
435 argc);
436 Object* code = map->FindInCodeCache(name, flags);
437 if (code->IsUndefined()) {
438 if (object->IsJSObject()) {
439 Object* opt =
440 Top::LookupSpecialFunction(JSObject::cast(object), holder, function);
441 if (opt->IsJSFunction()) {
442 check = StubCompiler::JSARRAY_HAS_FAST_ELEMENTS_CHECK;
443 function = JSFunction::cast(opt);
444 }
445 }
446 // If the function hasn't been compiled yet, we cannot do it now
447 // because it may cause GC. To avoid this issue, we return an
448 // internal error which will make sure we do not update any
449 // caches.
450 if (!function->is_compiled()) return Failure::InternalError();
451 // Compile the stub - only create stubs for fully compiled functions.
452 CallStubCompiler compiler(argc, in_loop);
453 code = compiler.CompileCallConstant(object, holder, function, name, check);
454 if (code->IsFailure()) return code;
455 ASSERT_EQ(flags, Code::cast(code)->flags());
456 LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
457 Object* result = map->UpdateCodeCache(name, Code::cast(code));
458 if (result->IsFailure()) return result;
459 }
460 return Set(name, map, Code::cast(code));
461}
462
463
464Object* StubCache::ComputeCallField(int argc,
465 InLoopFlag in_loop,
466 String* name,
467 Object* object,
468 JSObject* holder,
469 int index) {
470 // Compute the check type and the map.
471 Map* map = IC::GetCodeCacheMapForObject(object);
472
473 // TODO(1233596): We cannot do receiver map check for non-JS objects
474 // because they may be represented as immediates without a
475 // map. Instead, we check against the map in the holder.
476 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
477 object = holder;
478 }
479
480 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC,
481 FIELD,
482 in_loop,
483 argc);
484 Object* code = map->FindInCodeCache(name, flags);
485 if (code->IsUndefined()) {
486 CallStubCompiler compiler(argc, in_loop);
487 code = compiler.CompileCallField(object, holder, index, name);
488 if (code->IsFailure()) return code;
489 ASSERT_EQ(flags, Code::cast(code)->flags());
490 LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
491 Object* result = map->UpdateCodeCache(name, Code::cast(code));
492 if (result->IsFailure()) return result;
493 }
494 return Set(name, map, Code::cast(code));
495}
496
497
498Object* StubCache::ComputeCallInterceptor(int argc,
499 String* name,
500 Object* object,
501 JSObject* holder) {
502 // Compute the check type and the map.
503 // If the object is a value, we use the prototype map for the cache.
504 Map* map = IC::GetCodeCacheMapForObject(object);
505
506 // TODO(1233596): We cannot do receiver map check for non-JS objects
507 // because they may be represented as immediates without a
508 // map. Instead, we check against the map in the holder.
509 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
510 object = holder;
511 }
512
513 Code::Flags flags =
514 Code::ComputeMonomorphicFlags(Code::CALL_IC,
515 INTERCEPTOR,
516 NOT_IN_LOOP,
517 argc);
518 Object* code = map->FindInCodeCache(name, flags);
519 if (code->IsUndefined()) {
520 CallStubCompiler compiler(argc, NOT_IN_LOOP);
521 code = compiler.CompileCallInterceptor(object, holder, name);
522 if (code->IsFailure()) return code;
523 ASSERT_EQ(flags, Code::cast(code)->flags());
524 LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
525 Object* result = map->UpdateCodeCache(name, Code::cast(code));
526 if (result->IsFailure()) return result;
527 }
528 return Set(name, map, Code::cast(code));
529}
530
531
532Object* StubCache::ComputeCallNormal(int argc,
533 InLoopFlag in_loop,
534 String* name,
535 JSObject* receiver) {
536 Object* code = ComputeCallNormal(argc, in_loop);
537 if (code->IsFailure()) return code;
538 return Set(name, receiver->map(), Code::cast(code));
539}
540
541
542Object* StubCache::ComputeCallGlobal(int argc,
543 InLoopFlag in_loop,
544 String* name,
545 JSObject* receiver,
546 GlobalObject* holder,
547 JSGlobalPropertyCell* cell,
548 JSFunction* function) {
549 Code::Flags flags =
550 Code::ComputeMonomorphicFlags(Code::CALL_IC, NORMAL, in_loop, argc);
551 Object* code = receiver->map()->FindInCodeCache(name, flags);
552 if (code->IsUndefined()) {
553 // If the function hasn't been compiled yet, we cannot do it now
554 // because it may cause GC. To avoid this issue, we return an
555 // internal error which will make sure we do not update any
556 // caches.
557 if (!function->is_compiled()) return Failure::InternalError();
558 CallStubCompiler compiler(argc, in_loop);
559 code = compiler.CompileCallGlobal(receiver, holder, cell, function, name);
560 if (code->IsFailure()) return code;
561 ASSERT_EQ(flags, Code::cast(code)->flags());
562 LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
563 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
564 if (result->IsFailure()) return code;
565 }
566 return Set(name, receiver->map(), Code::cast(code));
567}
568
569
570static Object* GetProbeValue(Code::Flags flags) {
571 // Use raw_unchecked... so we don't get assert failures during GC.
572 NumberDictionary* dictionary = Heap::raw_unchecked_non_monomorphic_cache();
573 int entry = dictionary->FindEntry(flags);
574 if (entry != -1) return dictionary->ValueAt(entry);
575 return Heap::raw_unchecked_undefined_value();
576}
577
578
579static Object* ProbeCache(Code::Flags flags) {
580 Object* probe = GetProbeValue(flags);
581 if (probe != Heap::undefined_value()) return probe;
582 // Seed the cache with an undefined value to make sure that any
583 // generated code object can always be inserted into the cache
584 // without causing allocation failures.
585 Object* result =
586 Heap::non_monomorphic_cache()->AtNumberPut(flags,
587 Heap::undefined_value());
588 if (result->IsFailure()) return result;
589 Heap::public_set_non_monomorphic_cache(NumberDictionary::cast(result));
590 return probe;
591}
592
593
594static Object* FillCache(Object* code) {
595 if (code->IsCode()) {
596 int entry =
597 Heap::non_monomorphic_cache()->FindEntry(
598 Code::cast(code)->flags());
599 // The entry must be present see comment in ProbeCache.
600 ASSERT(entry != -1);
601 ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) ==
602 Heap::undefined_value());
603 Heap::non_monomorphic_cache()->ValueAtPut(entry, code);
604 CHECK(GetProbeValue(Code::cast(code)->flags()) == code);
605 }
606 return code;
607}
608
609
610Code* StubCache::FindCallInitialize(int argc, InLoopFlag in_loop) {
611 Code::Flags flags =
612 Code::ComputeFlags(Code::CALL_IC, in_loop, UNINITIALIZED, NORMAL, argc);
613 Object* result = ProbeCache(flags);
614 ASSERT(!result->IsUndefined());
615 // This might be called during the marking phase of the collector
616 // hence the unchecked cast.
617 return reinterpret_cast<Code*>(result);
618}
619
620
621Object* StubCache::ComputeCallInitialize(int argc, InLoopFlag in_loop) {
622 Code::Flags flags =
623 Code::ComputeFlags(Code::CALL_IC, in_loop, UNINITIALIZED, NORMAL, argc);
624 Object* probe = ProbeCache(flags);
625 if (!probe->IsUndefined()) return probe;
626 StubCompiler compiler;
627 return FillCache(compiler.CompileCallInitialize(flags));
628}
629
630
631Object* StubCache::ComputeCallPreMonomorphic(int argc, InLoopFlag in_loop) {
632 Code::Flags flags =
633 Code::ComputeFlags(Code::CALL_IC, in_loop, PREMONOMORPHIC, NORMAL, argc);
634 Object* probe = ProbeCache(flags);
635 if (!probe->IsUndefined()) return probe;
636 StubCompiler compiler;
637 return FillCache(compiler.CompileCallPreMonomorphic(flags));
638}
639
640
641Object* StubCache::ComputeCallNormal(int argc, InLoopFlag in_loop) {
642 Code::Flags flags =
643 Code::ComputeFlags(Code::CALL_IC, in_loop, MONOMORPHIC, NORMAL, argc);
644 Object* probe = ProbeCache(flags);
645 if (!probe->IsUndefined()) return probe;
646 StubCompiler compiler;
647 return FillCache(compiler.CompileCallNormal(flags));
648}
649
650
651Object* StubCache::ComputeCallMegamorphic(int argc, InLoopFlag in_loop) {
652 Code::Flags flags =
653 Code::ComputeFlags(Code::CALL_IC, in_loop, MEGAMORPHIC, NORMAL, argc);
654 Object* probe = ProbeCache(flags);
655 if (!probe->IsUndefined()) return probe;
656 StubCompiler compiler;
657 return FillCache(compiler.CompileCallMegamorphic(flags));
658}
659
660
661Object* StubCache::ComputeCallMiss(int argc) {
662 Code::Flags flags =
663 Code::ComputeFlags(Code::STUB, NOT_IN_LOOP, MEGAMORPHIC, NORMAL, argc);
664 Object* probe = ProbeCache(flags);
665 if (!probe->IsUndefined()) return probe;
666 StubCompiler compiler;
667 return FillCache(compiler.CompileCallMiss(flags));
668}
669
670
671#ifdef ENABLE_DEBUGGER_SUPPORT
672Object* StubCache::ComputeCallDebugBreak(int argc) {
673 Code::Flags flags =
674 Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, DEBUG_BREAK, NORMAL, argc);
675 Object* probe = ProbeCache(flags);
676 if (!probe->IsUndefined()) return probe;
677 StubCompiler compiler;
678 return FillCache(compiler.CompileCallDebugBreak(flags));
679}
680
681
682Object* StubCache::ComputeCallDebugPrepareStepIn(int argc) {
683 Code::Flags flags =
684 Code::ComputeFlags(Code::CALL_IC,
685 NOT_IN_LOOP,
686 DEBUG_PREPARE_STEP_IN,
687 NORMAL,
688 argc);
689 Object* probe = ProbeCache(flags);
690 if (!probe->IsUndefined()) return probe;
691 StubCompiler compiler;
692 return FillCache(compiler.CompileCallDebugPrepareStepIn(flags));
693}
694#endif
695
696
697Object* StubCache::ComputeLazyCompile(int argc) {
698 Code::Flags flags =
699 Code::ComputeFlags(Code::STUB, NOT_IN_LOOP, UNINITIALIZED, NORMAL, argc);
700 Object* probe = ProbeCache(flags);
701 if (!probe->IsUndefined()) return probe;
702 StubCompiler compiler;
703 Object* result = FillCache(compiler.CompileLazyCompile(flags));
704 if (result->IsCode()) {
705 Code* code = Code::cast(result);
706 USE(code);
707 LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG,
708 code, code->arguments_count()));
709 }
710 return result;
711}
712
713
714void StubCache::Clear() {
715 for (int i = 0; i < kPrimaryTableSize; i++) {
716 primary_[i].key = Heap::empty_string();
717 primary_[i].value = Builtins::builtin(Builtins::Illegal);
718 }
719 for (int j = 0; j < kSecondaryTableSize; j++) {
720 secondary_[j].key = Heap::empty_string();
721 secondary_[j].value = Builtins::builtin(Builtins::Illegal);
722 }
723}
724
725
726// ------------------------------------------------------------------------
727// StubCompiler implementation.
728
729
730// Support function for computing call IC miss stubs.
731Handle<Code> ComputeCallMiss(int argc) {
732 CALL_HEAP_FUNCTION(StubCache::ComputeCallMiss(argc), Code);
733}
734
735
736
737Object* LoadCallbackProperty(Arguments args) {
738 AccessorInfo* callback = AccessorInfo::cast(args[2]);
739 Address getter_address = v8::ToCData<Address>(callback->getter());
740 v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
741 ASSERT(fun != NULL);
742 v8::AccessorInfo info(args.arguments());
743 HandleScope scope;
744 v8::Handle<v8::Value> result;
745 {
746 // Leaving JavaScript.
747 VMState state(EXTERNAL);
748 result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
749 }
750 RETURN_IF_SCHEDULED_EXCEPTION();
751 if (result.IsEmpty()) return Heap::undefined_value();
752 return *v8::Utils::OpenHandle(*result);
753}
754
755
756Object* StoreCallbackProperty(Arguments args) {
757 JSObject* recv = JSObject::cast(args[0]);
758 AccessorInfo* callback = AccessorInfo::cast(args[1]);
759 Address setter_address = v8::ToCData<Address>(callback->setter());
760 v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
761 ASSERT(fun != NULL);
762 Handle<String> name = args.at<String>(2);
763 Handle<Object> value = args.at<Object>(3);
764 HandleScope scope;
765 LOG(ApiNamedPropertyAccess("store", recv, *name));
766 CustomArguments custom_args(callback->data(), recv, recv);
767 v8::AccessorInfo info(custom_args.end());
768 {
769 // Leaving JavaScript.
770 VMState state(EXTERNAL);
771 fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
772 }
773 RETURN_IF_SCHEDULED_EXCEPTION();
774 return *value;
775}
776
777/**
778 * Attempts to load a property with an interceptor (which must be present),
779 * but doesn't search the prototype chain.
780 *
781 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
782 * provide any value for the given name.
783 */
784Object* LoadPropertyWithInterceptorOnly(Arguments args) {
785 JSObject* receiver_handle = JSObject::cast(args[0]);
786 JSObject* holder_handle = JSObject::cast(args[1]);
787 Handle<String> name_handle = args.at<String>(2);
788 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(3);
789 Object* data_handle = args[4];
790
791 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
792 v8::NamedPropertyGetter getter =
793 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
794 ASSERT(getter != NULL);
795
796 {
797 // Use the interceptor getter.
798 CustomArguments args(data_handle, receiver_handle, holder_handle);
799 v8::AccessorInfo info(args.end());
800 HandleScope scope;
801 v8::Handle<v8::Value> r;
802 {
803 // Leaving JavaScript.
804 VMState state(EXTERNAL);
805 r = getter(v8::Utils::ToLocal(name_handle), info);
806 }
807 RETURN_IF_SCHEDULED_EXCEPTION();
808 if (!r.IsEmpty()) {
809 return *v8::Utils::OpenHandle(*r);
810 }
811 }
812
813 return Heap::no_interceptor_result_sentinel();
814}
815
816
817static Object* ThrowReferenceError(String* name) {
818 // If the load is non-contextual, just return the undefined result.
819 // Note that both keyed and non-keyed loads may end up here, so we
820 // can't use either LoadIC or KeyedLoadIC constructors.
821 IC ic(IC::NO_EXTRA_FRAME);
822 ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
823 if (!ic.is_contextual()) return Heap::undefined_value();
824
825 // Throw a reference error.
826 HandleScope scope;
827 Handle<String> name_handle(name);
828 Handle<Object> error =
829 Factory::NewReferenceError("not_defined",
830 HandleVector(&name_handle, 1));
831 return Top::Throw(*error);
832}
833
834
835static Object* LoadWithInterceptor(Arguments* args,
836 PropertyAttributes* attrs) {
837 Handle<JSObject> receiver_handle = args->at<JSObject>(0);
838 Handle<JSObject> holder_handle = args->at<JSObject>(1);
839 Handle<String> name_handle = args->at<String>(2);
840 Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(3);
841 Handle<Object> data_handle = args->at<Object>(4);
842
843 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
844 v8::NamedPropertyGetter getter =
845 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
846 ASSERT(getter != NULL);
847
848 {
849 // Use the interceptor getter.
850 CustomArguments args(*data_handle, *receiver_handle, *holder_handle);
851 v8::AccessorInfo info(args.end());
852 HandleScope scope;
853 v8::Handle<v8::Value> r;
854 {
855 // Leaving JavaScript.
856 VMState state(EXTERNAL);
857 r = getter(v8::Utils::ToLocal(name_handle), info);
858 }
859 RETURN_IF_SCHEDULED_EXCEPTION();
860 if (!r.IsEmpty()) {
861 *attrs = NONE;
862 return *v8::Utils::OpenHandle(*r);
863 }
864 }
865
866 Object* result = holder_handle->GetPropertyPostInterceptor(
867 *receiver_handle,
868 *name_handle,
869 attrs);
870 RETURN_IF_SCHEDULED_EXCEPTION();
871 return result;
872}
873
874
875/**
876 * Loads a property with an interceptor performing post interceptor
877 * lookup if interceptor failed.
878 */
879Object* LoadPropertyWithInterceptorForLoad(Arguments args) {
880 PropertyAttributes attr = NONE;
881 Object* result = LoadWithInterceptor(&args, &attr);
882 if (result->IsFailure()) return result;
883
884 // If the property is present, return it.
885 if (attr != ABSENT) return result;
886 return ThrowReferenceError(String::cast(args[2]));
887}
888
889
890Object* LoadPropertyWithInterceptorForCall(Arguments args) {
891 PropertyAttributes attr;
892 Object* result = LoadWithInterceptor(&args, &attr);
893 RETURN_IF_SCHEDULED_EXCEPTION();
894 // This is call IC. In this case, we simply return the undefined result which
895 // will lead to an exception when trying to invoke the result as a
896 // function.
897 return result;
898}
899
900
901Object* StoreInterceptorProperty(Arguments args) {
902 JSObject* recv = JSObject::cast(args[0]);
903 String* name = String::cast(args[1]);
904 Object* value = args[2];
905 ASSERT(recv->HasNamedInterceptor());
906 PropertyAttributes attr = NONE;
907 Object* result = recv->SetPropertyWithInterceptor(name, value, attr);
908 return result;
909}
910
911
912Object* StubCompiler::CompileCallInitialize(Code::Flags flags) {
913 HandleScope scope;
914 int argc = Code::ExtractArgumentsCountFromFlags(flags);
915 CallIC::GenerateInitialize(masm(), argc);
916 Object* result = GetCodeWithFlags(flags, "CompileCallInitialize");
917 if (!result->IsFailure()) {
918 Counters::call_initialize_stubs.Increment();
919 Code* code = Code::cast(result);
920 USE(code);
921 LOG(CodeCreateEvent(Logger::CALL_INITIALIZE_TAG,
922 code, code->arguments_count()));
923 }
924 return result;
925}
926
927
928Object* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
929 HandleScope scope;
930 int argc = Code::ExtractArgumentsCountFromFlags(flags);
931 // The code of the PreMonomorphic stub is the same as the code
932 // of the Initialized stub. They just differ on the code object flags.
933 CallIC::GenerateInitialize(masm(), argc);
934 Object* result = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
935 if (!result->IsFailure()) {
936 Counters::call_premonomorphic_stubs.Increment();
937 Code* code = Code::cast(result);
938 USE(code);
939 LOG(CodeCreateEvent(Logger::CALL_PRE_MONOMORPHIC_TAG,
940 code, code->arguments_count()));
941 }
942 return result;
943}
944
945
946Object* StubCompiler::CompileCallNormal(Code::Flags flags) {
947 HandleScope scope;
948 int argc = Code::ExtractArgumentsCountFromFlags(flags);
949 CallIC::GenerateNormal(masm(), argc);
950 Object* result = GetCodeWithFlags(flags, "CompileCallNormal");
951 if (!result->IsFailure()) {
952 Counters::call_normal_stubs.Increment();
953 Code* code = Code::cast(result);
954 USE(code);
955 LOG(CodeCreateEvent(Logger::CALL_NORMAL_TAG,
956 code, code->arguments_count()));
957 }
958 return result;
959}
960
961
962Object* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
963 HandleScope scope;
964 int argc = Code::ExtractArgumentsCountFromFlags(flags);
965 CallIC::GenerateMegamorphic(masm(), argc);
966 Object* result = GetCodeWithFlags(flags, "CompileCallMegamorphic");
967 if (!result->IsFailure()) {
968 Counters::call_megamorphic_stubs.Increment();
969 Code* code = Code::cast(result);
970 USE(code);
971 LOG(CodeCreateEvent(Logger::CALL_MEGAMORPHIC_TAG,
972 code, code->arguments_count()));
973 }
974 return result;
975}
976
977
978Object* StubCompiler::CompileCallMiss(Code::Flags flags) {
979 HandleScope scope;
980 int argc = Code::ExtractArgumentsCountFromFlags(flags);
981 CallIC::GenerateMiss(masm(), argc);
982 Object* result = GetCodeWithFlags(flags, "CompileCallMiss");
983 if (!result->IsFailure()) {
984 Counters::call_megamorphic_stubs.Increment();
985 Code* code = Code::cast(result);
986 USE(code);
987 LOG(CodeCreateEvent(Logger::CALL_MISS_TAG, code, code->arguments_count()));
988 }
989 return result;
990}
991
992
993#ifdef ENABLE_DEBUGGER_SUPPORT
994Object* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
995 HandleScope scope;
996 Debug::GenerateCallICDebugBreak(masm());
997 Object* result = GetCodeWithFlags(flags, "CompileCallDebugBreak");
998 if (!result->IsFailure()) {
999 Code* code = Code::cast(result);
1000 USE(code);
1001 LOG(CodeCreateEvent(Logger::CALL_DEBUG_BREAK_TAG,
1002 code, code->arguments_count()));
1003 }
1004 return result;
1005}
1006
1007
1008Object* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
1009 HandleScope scope;
1010 // Use the same code for the the step in preparations as we do for
1011 // the miss case.
1012 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1013 CallIC::GenerateMiss(masm(), argc);
1014 Object* result = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1015 if (!result->IsFailure()) {
1016 Code* code = Code::cast(result);
1017 USE(code);
1018 LOG(CodeCreateEvent(Logger::CALL_DEBUG_PREPARE_STEP_IN_TAG,
1019 code, code->arguments_count()));
1020 }
1021 return result;
1022}
1023#endif
1024
1025
1026Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, const char* name) {
1027 // Check for allocation failures during stub compilation.
1028 if (failure_->IsFailure()) return failure_;
1029
1030 // Create code object in the heap.
1031 CodeDesc desc;
1032 masm_.GetCode(&desc);
1033 Object* result = Heap::CreateCode(desc, NULL, flags, masm_.CodeObject());
1034#ifdef ENABLE_DISASSEMBLER
1035 if (FLAG_print_code_stubs && !result->IsFailure()) {
1036 Code::cast(result)->Disassemble(name);
1037 }
1038#endif
1039 return result;
1040}
1041
1042
1043Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
1044 if (FLAG_print_code_stubs && (name != NULL)) {
1045 return GetCodeWithFlags(flags, *name->ToCString());
1046 }
1047 return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1048}
1049
1050
1051Object* LoadStubCompiler::GetCode(PropertyType type, String* name) {
1052 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
1053 return GetCodeWithFlags(flags, name);
1054}
1055
1056
1057Object* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
1058 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
1059 return GetCodeWithFlags(flags, name);
1060}
1061
1062
1063Object* StoreStubCompiler::GetCode(PropertyType type, String* name) {
1064 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
1065 return GetCodeWithFlags(flags, name);
1066}
1067
1068
1069Object* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
1070 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
1071 return GetCodeWithFlags(flags, name);
1072}
1073
1074
1075Object* CallStubCompiler::GetCode(PropertyType type, String* name) {
1076 int argc = arguments_.immediate();
1077 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC,
1078 type,
1079 in_loop_,
1080 argc);
1081 return GetCodeWithFlags(flags, name);
1082}
1083
1084
1085Object* ConstructStubCompiler::GetCode() {
1086 Code::Flags flags = Code::ComputeFlags(Code::STUB);
1087 Object* result = GetCodeWithFlags(flags, "ConstructStub");
1088 if (!result->IsFailure()) {
1089 Code* code = Code::cast(result);
1090 USE(code);
1091 LOG(CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
1092 }
1093 return result;
1094}
1095
1096
1097} } // namespace v8::internal