1 // 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 "gdb-jit.h"
33 #include "ic-inl.h"
34 #include "stub-cache.h"
35 #include "vm-state-inl.h"
36
37 namespace v8 {
38 namespace internal {
39
40 // -----------------------------------------------------------------------
41 // StubCache implementation.
42
43
StubCache(Isolate * isolate)44 StubCache::StubCache(Isolate* isolate) : isolate_(isolate) {
45 ASSERT(isolate == Isolate::Current());
46 memset(primary_, 0, sizeof(primary_[0]) * StubCache::kPrimaryTableSize);
47 memset(secondary_, 0, sizeof(secondary_[0]) * StubCache::kSecondaryTableSize);
48 }
49
50
Initialize(bool create_heap_objects)51 void StubCache::Initialize(bool create_heap_objects) {
52 ASSERT(IsPowerOf2(kPrimaryTableSize));
53 ASSERT(IsPowerOf2(kSecondaryTableSize));
54 if (create_heap_objects) {
55 HandleScope scope;
56 Clear();
57 }
58 }
59
60
Set(String * name,Map * map,Code * code)61 Code* StubCache::Set(String* name, Map* map, Code* code) {
62 // Get the flags from the code.
63 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
64
65 // Validate that the name does not move on scavenge, and that we
66 // can use identity checks instead of string equality checks.
67 ASSERT(!heap()->InNewSpace(name));
68 ASSERT(name->IsSymbol());
69
70 // The state bits are not important to the hash function because
71 // the stub cache only contains monomorphic stubs. Make sure that
72 // the bits are the least significant so they will be the ones
73 // masked out.
74 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
75 ASSERT(Code::kFlagsICStateShift == 0);
76
77 // Make sure that the code type is not included in the hash.
78 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
79
80 // Compute the primary entry.
81 int primary_offset = PrimaryOffset(name, flags, map);
82 Entry* primary = entry(primary_, primary_offset);
83 Code* hit = primary->value;
84
85 // If the primary entry has useful data in it, we retire it to the
86 // secondary cache before overwriting it.
87 if (hit != isolate_->builtins()->builtin(Builtins::kIllegal)) {
88 Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
89 int secondary_offset =
90 SecondaryOffset(primary->key, primary_flags, primary_offset);
91 Entry* secondary = entry(secondary_, secondary_offset);
92 *secondary = *primary;
93 }
94
95 // Update primary cache.
96 primary->key = name;
97 primary->value = code;
98 return code;
99 }
100
101
ComputeLoadNonexistent(String * name,JSObject * receiver)102 MaybeObject* StubCache::ComputeLoadNonexistent(String* name,
103 JSObject* receiver) {
104 ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties());
105 // If no global objects are present in the prototype chain, the load
106 // nonexistent IC stub can be shared for all names for a given map
107 // and we use the empty string for the map cache in that case. If
108 // there are global objects involved, we need to check global
109 // property cells in the stub and therefore the stub will be
110 // specific to the name.
111 String* cache_name = heap()->empty_string();
112 if (receiver->IsGlobalObject()) cache_name = name;
113 JSObject* last = receiver;
114 while (last->GetPrototype() != heap()->null_value()) {
115 last = JSObject::cast(last->GetPrototype());
116 if (last->IsGlobalObject()) cache_name = name;
117 }
118 // Compile the stub that is either shared for all names or
119 // name specific if there are global objects involved.
120 Code::Flags flags =
121 Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT);
122 Object* code = receiver->map()->FindInCodeCache(cache_name, flags);
123 if (code->IsUndefined()) {
124 LoadStubCompiler compiler;
125 { MaybeObject* maybe_code =
126 compiler.CompileLoadNonexistent(cache_name, receiver, last);
127 if (!maybe_code->ToObject(&code)) return maybe_code;
128 }
129 PROFILE(isolate_,
130 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name));
131 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, cache_name, Code::cast(code)));
132 Object* result;
133 { MaybeObject* maybe_result =
134 receiver->UpdateMapCodeCache(cache_name, Code::cast(code));
135 if (!maybe_result->ToObject(&result)) return maybe_result;
136 }
137 }
138 return code;
139 }
140
141
ComputeLoadField(String * name,JSObject * receiver,JSObject * holder,int field_index)142 MaybeObject* StubCache::ComputeLoadField(String* name,
143 JSObject* receiver,
144 JSObject* holder,
145 int field_index) {
146 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
147 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
148 Object* code = receiver->map()->FindInCodeCache(name, flags);
149 if (code->IsUndefined()) {
150 LoadStubCompiler compiler;
151 { MaybeObject* maybe_code =
152 compiler.CompileLoadField(receiver, holder, field_index, name);
153 if (!maybe_code->ToObject(&code)) return maybe_code;
154 }
155 PROFILE(isolate_,
156 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
157 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
158 Object* result;
159 { MaybeObject* maybe_result =
160 receiver->UpdateMapCodeCache(name, Code::cast(code));
161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
163 }
164 return code;
165 }
166
167
ComputeLoadCallback(String * name,JSObject * receiver,JSObject * holder,AccessorInfo * callback)168 MaybeObject* StubCache::ComputeLoadCallback(String* name,
169 JSObject* receiver,
170 JSObject* holder,
171 AccessorInfo* callback) {
172 ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
173 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
174 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
175 Object* code = receiver->map()->FindInCodeCache(name, flags);
176 if (code->IsUndefined()) {
177 LoadStubCompiler compiler;
178 { MaybeObject* maybe_code =
179 compiler.CompileLoadCallback(name, receiver, holder, callback);
180 if (!maybe_code->ToObject(&code)) return maybe_code;
181 }
182 PROFILE(isolate_,
183 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
184 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
185 Object* result;
186 { MaybeObject* maybe_result =
187 receiver->UpdateMapCodeCache(name, Code::cast(code));
188 if (!maybe_result->ToObject(&result)) return maybe_result;
189 }
190 }
191 return code;
192 }
193
194
ComputeLoadConstant(String * name,JSObject * receiver,JSObject * holder,Object * value)195 MaybeObject* StubCache::ComputeLoadConstant(String* name,
196 JSObject* receiver,
197 JSObject* holder,
198 Object* value) {
199 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
200 Code::Flags flags =
201 Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
202 Object* code = receiver->map()->FindInCodeCache(name, flags);
203 if (code->IsUndefined()) {
204 LoadStubCompiler compiler;
205 { MaybeObject* maybe_code =
206 compiler.CompileLoadConstant(receiver, holder, value, name);
207 if (!maybe_code->ToObject(&code)) return maybe_code;
208 }
209 PROFILE(isolate_,
210 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
211 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
212 Object* result;
213 { MaybeObject* maybe_result =
214 receiver->UpdateMapCodeCache(name, Code::cast(code));
215 if (!maybe_result->ToObject(&result)) return maybe_result;
216 }
217 }
218 return code;
219 }
220
221
ComputeLoadInterceptor(String * name,JSObject * receiver,JSObject * holder)222 MaybeObject* StubCache::ComputeLoadInterceptor(String* name,
223 JSObject* receiver,
224 JSObject* holder) {
225 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
226 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
227 Object* code = receiver->map()->FindInCodeCache(name, flags);
228 if (code->IsUndefined()) {
229 LoadStubCompiler compiler;
230 { MaybeObject* maybe_code =
231 compiler.CompileLoadInterceptor(receiver, holder, name);
232 if (!maybe_code->ToObject(&code)) return maybe_code;
233 }
234 PROFILE(isolate_,
235 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
236 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
237 Object* result;
238 { MaybeObject* maybe_result =
239 receiver->UpdateMapCodeCache(name, Code::cast(code));
240 if (!maybe_result->ToObject(&result)) return maybe_result;
241 }
242 }
243 return code;
244 }
245
246
ComputeLoadNormal()247 MaybeObject* StubCache::ComputeLoadNormal() {
248 return isolate_->builtins()->builtin(Builtins::kLoadIC_Normal);
249 }
250
251
ComputeLoadGlobal(String * name,JSObject * receiver,GlobalObject * holder,JSGlobalPropertyCell * cell,bool is_dont_delete)252 MaybeObject* StubCache::ComputeLoadGlobal(String* name,
253 JSObject* receiver,
254 GlobalObject* holder,
255 JSGlobalPropertyCell* cell,
256 bool is_dont_delete) {
257 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
258 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
259 Object* code = receiver->map()->FindInCodeCache(name, flags);
260 if (code->IsUndefined()) {
261 LoadStubCompiler compiler;
262 { MaybeObject* maybe_code = compiler.CompileLoadGlobal(receiver,
263 holder,
264 cell,
265 name,
266 is_dont_delete);
267 if (!maybe_code->ToObject(&code)) return maybe_code;
268 }
269 PROFILE(isolate_,
270 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
271 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
272 Object* result;
273 { MaybeObject* maybe_result =
274 receiver->UpdateMapCodeCache(name, Code::cast(code));
275 if (!maybe_result->ToObject(&result)) return maybe_result;
276 }
277 }
278 return code;
279 }
280
281
ComputeKeyedLoadField(String * name,JSObject * receiver,JSObject * holder,int field_index)282 MaybeObject* StubCache::ComputeKeyedLoadField(String* name,
283 JSObject* receiver,
284 JSObject* holder,
285 int field_index) {
286 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
287 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
288 Object* code = receiver->map()->FindInCodeCache(name, flags);
289 if (code->IsUndefined()) {
290 KeyedLoadStubCompiler compiler;
291 { MaybeObject* maybe_code =
292 compiler.CompileLoadField(name, receiver, holder, field_index);
293 if (!maybe_code->ToObject(&code)) return maybe_code;
294 }
295 PROFILE(isolate_,
296 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
297 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
298 Object* result;
299 { MaybeObject* maybe_result =
300 receiver->UpdateMapCodeCache(name, Code::cast(code));
301 if (!maybe_result->ToObject(&result)) return maybe_result;
302 }
303 }
304 return code;
305 }
306
307
ComputeKeyedLoadConstant(String * name,JSObject * receiver,JSObject * holder,Object * value)308 MaybeObject* StubCache::ComputeKeyedLoadConstant(String* name,
309 JSObject* receiver,
310 JSObject* holder,
311 Object* value) {
312 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
313 Code::Flags flags =
314 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
315 Object* code = receiver->map()->FindInCodeCache(name, flags);
316 if (code->IsUndefined()) {
317 KeyedLoadStubCompiler compiler;
318 { MaybeObject* maybe_code =
319 compiler.CompileLoadConstant(name, receiver, holder, value);
320 if (!maybe_code->ToObject(&code)) return maybe_code;
321 }
322 PROFILE(isolate_,
323 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
324 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
325 Object* result;
326 { MaybeObject* maybe_result =
327 receiver->UpdateMapCodeCache(name, Code::cast(code));
328 if (!maybe_result->ToObject(&result)) return maybe_result;
329 }
330 }
331 return code;
332 }
333
334
ComputeKeyedLoadInterceptor(String * name,JSObject * receiver,JSObject * holder)335 MaybeObject* StubCache::ComputeKeyedLoadInterceptor(String* name,
336 JSObject* receiver,
337 JSObject* holder) {
338 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
339 Code::Flags flags =
340 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
341 Object* code = receiver->map()->FindInCodeCache(name, flags);
342 if (code->IsUndefined()) {
343 KeyedLoadStubCompiler compiler;
344 { MaybeObject* maybe_code =
345 compiler.CompileLoadInterceptor(receiver, holder, name);
346 if (!maybe_code->ToObject(&code)) return maybe_code;
347 }
348 PROFILE(isolate_,
349 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
350 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
351 Object* result;
352 { MaybeObject* maybe_result =
353 receiver->UpdateMapCodeCache(name, Code::cast(code));
354 if (!maybe_result->ToObject(&result)) return maybe_result;
355 }
356 }
357 return code;
358 }
359
360
ComputeKeyedLoadCallback(String * name,JSObject * receiver,JSObject * holder,AccessorInfo * callback)361 MaybeObject* StubCache::ComputeKeyedLoadCallback(String* name,
362 JSObject* receiver,
363 JSObject* holder,
364 AccessorInfo* callback) {
365 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
366 Code::Flags flags =
367 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
368 Object* code = receiver->map()->FindInCodeCache(name, flags);
369 if (code->IsUndefined()) {
370 KeyedLoadStubCompiler compiler;
371 { MaybeObject* maybe_code =
372 compiler.CompileLoadCallback(name, receiver, holder, callback);
373 if (!maybe_code->ToObject(&code)) return maybe_code;
374 }
375 PROFILE(isolate_,
376 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
377 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
378 Object* result;
379 { MaybeObject* maybe_result =
380 receiver->UpdateMapCodeCache(name, Code::cast(code));
381 if (!maybe_result->ToObject(&result)) return maybe_result;
382 }
383 }
384 return code;
385 }
386
387
388
ComputeKeyedLoadArrayLength(String * name,JSArray * receiver)389 MaybeObject* StubCache::ComputeKeyedLoadArrayLength(String* name,
390 JSArray* receiver) {
391 Code::Flags flags =
392 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
393 ASSERT(receiver->IsJSObject());
394 Object* code = receiver->map()->FindInCodeCache(name, flags);
395 if (code->IsUndefined()) {
396 KeyedLoadStubCompiler compiler;
397 { MaybeObject* maybe_code = compiler.CompileLoadArrayLength(name);
398 if (!maybe_code->ToObject(&code)) return maybe_code;
399 }
400 PROFILE(isolate_,
401 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
402 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
403 Object* result;
404 { MaybeObject* maybe_result =
405 receiver->UpdateMapCodeCache(name, Code::cast(code));
406 if (!maybe_result->ToObject(&result)) return maybe_result;
407 }
408 }
409 return code;
410 }
411
412
ComputeKeyedLoadStringLength(String * name,String * receiver)413 MaybeObject* StubCache::ComputeKeyedLoadStringLength(String* name,
414 String* receiver) {
415 Code::Flags flags =
416 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
417 Map* map = receiver->map();
418 Object* code = map->FindInCodeCache(name, flags);
419 if (code->IsUndefined()) {
420 KeyedLoadStubCompiler compiler;
421 { MaybeObject* maybe_code = compiler.CompileLoadStringLength(name);
422 if (!maybe_code->ToObject(&code)) return maybe_code;
423 }
424 PROFILE(isolate_,
425 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
426 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
427 Object* result;
428 { MaybeObject* maybe_result = map->UpdateCodeCache(name, Code::cast(code));
429 if (!maybe_result->ToObject(&result)) return maybe_result;
430 }
431 }
432 return code;
433 }
434
435
ComputeKeyedLoadFunctionPrototype(String * name,JSFunction * receiver)436 MaybeObject* StubCache::ComputeKeyedLoadFunctionPrototype(
437 String* name,
438 JSFunction* receiver) {
439 Code::Flags flags =
440 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
441 Object* code = receiver->map()->FindInCodeCache(name, flags);
442 if (code->IsUndefined()) {
443 KeyedLoadStubCompiler compiler;
444 { MaybeObject* maybe_code = compiler.CompileLoadFunctionPrototype(name);
445 if (!maybe_code->ToObject(&code)) return maybe_code;
446 }
447 PROFILE(isolate_,
448 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
449 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
450 Object* result;
451 { MaybeObject* maybe_result =
452 receiver->UpdateMapCodeCache(name, Code::cast(code));
453 if (!maybe_result->ToObject(&result)) return maybe_result;
454 }
455 }
456 return code;
457 }
458
459
ComputeKeyedLoadSpecialized(JSObject * receiver)460 MaybeObject* StubCache::ComputeKeyedLoadSpecialized(JSObject* receiver) {
461 // Using NORMAL as the PropertyType for array element loads is a misuse. The
462 // generated stub always accesses fast elements, not slow-mode fields, but
463 // some property type is required for the stub lookup. Note that overloading
464 // the NORMAL PropertyType is only safe as long as no stubs are generated for
465 // other keyed field loads. This is guaranteed to be the case since all field
466 // keyed loads that are not array elements go through a generic builtin stub.
467 Code::Flags flags =
468 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, NORMAL);
469 String* name = heap()->KeyedLoadSpecialized_symbol();
470 Object* code = receiver->map()->FindInCodeCache(name, flags);
471 if (code->IsUndefined()) {
472 KeyedLoadStubCompiler compiler;
473 { MaybeObject* maybe_code = compiler.CompileLoadSpecialized(receiver);
474 if (!maybe_code->ToObject(&code)) return maybe_code;
475 }
476 PROFILE(isolate_,
477 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
478 Object* result;
479 { MaybeObject* maybe_result =
480 receiver->UpdateMapCodeCache(name, Code::cast(code));
481 if (!maybe_result->ToObject(&result)) return maybe_result;
482 }
483 }
484 return code;
485 }
486
487
ComputeStoreField(String * name,JSObject * receiver,int field_index,Map * transition,StrictModeFlag strict_mode)488 MaybeObject* StubCache::ComputeStoreField(String* name,
489 JSObject* receiver,
490 int field_index,
491 Map* transition,
492 StrictModeFlag strict_mode) {
493 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
494 Code::Flags flags = Code::ComputeMonomorphicFlags(
495 Code::STORE_IC, type, strict_mode);
496 Object* code = receiver->map()->FindInCodeCache(name, flags);
497 if (code->IsUndefined()) {
498 StoreStubCompiler compiler(strict_mode);
499 { MaybeObject* maybe_code =
500 compiler.CompileStoreField(receiver, field_index, transition, name);
501 if (!maybe_code->ToObject(&code)) return maybe_code;
502 }
503 PROFILE(isolate_,
504 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
505 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
506 Object* result;
507 { MaybeObject* maybe_result =
508 receiver->UpdateMapCodeCache(name, Code::cast(code));
509 if (!maybe_result->ToObject(&result)) return maybe_result;
510 }
511 }
512 return code;
513 }
514
515
ComputeKeyedStoreSpecialized(JSObject * receiver,StrictModeFlag strict_mode)516 MaybeObject* StubCache::ComputeKeyedStoreSpecialized(
517 JSObject* receiver,
518 StrictModeFlag strict_mode) {
519 Code::Flags flags =
520 Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL, strict_mode);
521 String* name = heap()->KeyedStoreSpecialized_symbol();
522 Object* code = receiver->map()->FindInCodeCache(name, flags);
523 if (code->IsUndefined()) {
524 KeyedStoreStubCompiler compiler(strict_mode);
525 { MaybeObject* maybe_code = compiler.CompileStoreSpecialized(receiver);
526 if (!maybe_code->ToObject(&code)) return maybe_code;
527 }
528 PROFILE(isolate_,
529 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
530 Object* result;
531 { MaybeObject* maybe_result =
532 receiver->UpdateMapCodeCache(name, Code::cast(code));
533 if (!maybe_result->ToObject(&result)) return maybe_result;
534 }
535 }
536 return code;
537 }
538
539
540 namespace {
541
ElementsKindToExternalArrayType(JSObject::ElementsKind kind)542 ExternalArrayType ElementsKindToExternalArrayType(JSObject::ElementsKind kind) {
543 switch (kind) {
544 case JSObject::EXTERNAL_BYTE_ELEMENTS:
545 return kExternalByteArray;
546 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
547 return kExternalUnsignedByteArray;
548 case JSObject::EXTERNAL_SHORT_ELEMENTS:
549 return kExternalShortArray;
550 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
551 return kExternalUnsignedShortArray;
552 case JSObject::EXTERNAL_INT_ELEMENTS:
553 return kExternalIntArray;
554 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
555 return kExternalUnsignedIntArray;
556 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
557 return kExternalFloatArray;
558 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
559 return kExternalPixelArray;
560 default:
561 UNREACHABLE();
562 return static_cast<ExternalArrayType>(0);
563 }
564 }
565
ExternalArrayTypeToStubName(Heap * heap,ExternalArrayType array_type,bool is_store)566 String* ExternalArrayTypeToStubName(Heap* heap,
567 ExternalArrayType array_type,
568 bool is_store) {
569 if (is_store) {
570 switch (array_type) {
571 case kExternalByteArray:
572 return heap->KeyedStoreExternalByteArray_symbol();
573 case kExternalUnsignedByteArray:
574 return heap->KeyedStoreExternalUnsignedByteArray_symbol();
575 case kExternalShortArray:
576 return heap->KeyedStoreExternalShortArray_symbol();
577 case kExternalUnsignedShortArray:
578 return heap->KeyedStoreExternalUnsignedShortArray_symbol();
579 case kExternalIntArray:
580 return heap->KeyedStoreExternalIntArray_symbol();
581 case kExternalUnsignedIntArray:
582 return heap->KeyedStoreExternalUnsignedIntArray_symbol();
583 case kExternalFloatArray:
584 return heap->KeyedStoreExternalFloatArray_symbol();
585 case kExternalPixelArray:
586 return heap->KeyedStoreExternalPixelArray_symbol();
587 default:
588 UNREACHABLE();
589 return NULL;
590 }
591 } else {
592 switch (array_type) {
593 case kExternalByteArray:
594 return heap->KeyedLoadExternalByteArray_symbol();
595 case kExternalUnsignedByteArray:
596 return heap->KeyedLoadExternalUnsignedByteArray_symbol();
597 case kExternalShortArray:
598 return heap->KeyedLoadExternalShortArray_symbol();
599 case kExternalUnsignedShortArray:
600 return heap->KeyedLoadExternalUnsignedShortArray_symbol();
601 case kExternalIntArray:
602 return heap->KeyedLoadExternalIntArray_symbol();
603 case kExternalUnsignedIntArray:
604 return heap->KeyedLoadExternalUnsignedIntArray_symbol();
605 case kExternalFloatArray:
606 return heap->KeyedLoadExternalFloatArray_symbol();
607 case kExternalPixelArray:
608 return heap->KeyedLoadExternalPixelArray_symbol();
609 default:
610 UNREACHABLE();
611 return NULL;
612 }
613 }
614 }
615
616 } // anonymous namespace
617
618
ComputeKeyedLoadOrStoreExternalArray(JSObject * receiver,bool is_store,StrictModeFlag strict_mode)619 MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray(
620 JSObject* receiver,
621 bool is_store,
622 StrictModeFlag strict_mode) {
623 Code::Flags flags =
624 Code::ComputeMonomorphicFlags(
625 is_store ? Code::KEYED_EXTERNAL_ARRAY_STORE_IC :
626 Code::KEYED_EXTERNAL_ARRAY_LOAD_IC,
627 NORMAL,
628 strict_mode);
629 ExternalArrayType array_type =
630 ElementsKindToExternalArrayType(receiver->GetElementsKind());
631 String* name = ExternalArrayTypeToStubName(heap(), array_type, is_store);
632 Object* code = receiver->map()->FindInCodeCache(name, flags);
633 if (code->IsUndefined()) {
634 ExternalArrayStubCompiler compiler;
635 { MaybeObject* maybe_code =
636 is_store ?
637 compiler.CompileKeyedStoreStub(receiver, array_type, flags) :
638 compiler.CompileKeyedLoadStub(receiver, array_type, flags);
639 if (!maybe_code->ToObject(&code)) return maybe_code;
640 }
641 Code::cast(code)->set_external_array_type(array_type);
642 if (is_store) {
643 PROFILE(isolate_,
644 CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_STORE_IC_TAG,
645 Code::cast(code), 0));
646 } else {
647 PROFILE(isolate_,
648 CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG,
649 Code::cast(code), 0));
650 }
651 Object* result;
652 { MaybeObject* maybe_result =
653 receiver->UpdateMapCodeCache(name, Code::cast(code));
654 if (!maybe_result->ToObject(&result)) return maybe_result;
655 }
656 }
657 return code;
658 }
659
660
ComputeStoreNormal(StrictModeFlag strict_mode)661 MaybeObject* StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
662 return isolate_->builtins()->builtin((strict_mode == kStrictMode)
663 ? Builtins::kStoreIC_Normal_Strict
664 : Builtins::kStoreIC_Normal);
665 }
666
667
ComputeStoreGlobal(String * name,GlobalObject * receiver,JSGlobalPropertyCell * cell,StrictModeFlag strict_mode)668 MaybeObject* StubCache::ComputeStoreGlobal(String* name,
669 GlobalObject* receiver,
670 JSGlobalPropertyCell* cell,
671 StrictModeFlag strict_mode) {
672 Code::Flags flags = Code::ComputeMonomorphicFlags(
673 Code::STORE_IC, NORMAL, strict_mode);
674 Object* code = receiver->map()->FindInCodeCache(name, flags);
675 if (code->IsUndefined()) {
676 StoreStubCompiler compiler(strict_mode);
677 { MaybeObject* maybe_code =
678 compiler.CompileStoreGlobal(receiver, cell, name);
679 if (!maybe_code->ToObject(&code)) return maybe_code;
680 }
681 PROFILE(isolate_,
682 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
683 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
684 Object* result;
685 { MaybeObject* maybe_result =
686 receiver->UpdateMapCodeCache(name, Code::cast(code));
687 if (!maybe_result->ToObject(&result)) return maybe_result;
688 }
689 }
690 return code;
691 }
692
693
ComputeStoreCallback(String * name,JSObject * receiver,AccessorInfo * callback,StrictModeFlag strict_mode)694 MaybeObject* StubCache::ComputeStoreCallback(
695 String* name,
696 JSObject* receiver,
697 AccessorInfo* callback,
698 StrictModeFlag strict_mode) {
699 ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
700 Code::Flags flags = Code::ComputeMonomorphicFlags(
701 Code::STORE_IC, CALLBACKS, strict_mode);
702 Object* code = receiver->map()->FindInCodeCache(name, flags);
703 if (code->IsUndefined()) {
704 StoreStubCompiler compiler(strict_mode);
705 { MaybeObject* maybe_code =
706 compiler.CompileStoreCallback(receiver, callback, name);
707 if (!maybe_code->ToObject(&code)) return maybe_code;
708 }
709 PROFILE(isolate_,
710 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
711 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
712 Object* result;
713 { MaybeObject* maybe_result =
714 receiver->UpdateMapCodeCache(name, Code::cast(code));
715 if (!maybe_result->ToObject(&result)) return maybe_result;
716 }
717 }
718 return code;
719 }
720
721
ComputeStoreInterceptor(String * name,JSObject * receiver,StrictModeFlag strict_mode)722 MaybeObject* StubCache::ComputeStoreInterceptor(
723 String* name,
724 JSObject* receiver,
725 StrictModeFlag strict_mode) {
726 Code::Flags flags = Code::ComputeMonomorphicFlags(
727 Code::STORE_IC, INTERCEPTOR, strict_mode);
728 Object* code = receiver->map()->FindInCodeCache(name, flags);
729 if (code->IsUndefined()) {
730 StoreStubCompiler compiler(strict_mode);
731 { MaybeObject* maybe_code =
732 compiler.CompileStoreInterceptor(receiver, name);
733 if (!maybe_code->ToObject(&code)) return maybe_code;
734 }
735 PROFILE(isolate_,
736 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
737 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
738 Object* result;
739 { MaybeObject* maybe_result =
740 receiver->UpdateMapCodeCache(name, Code::cast(code));
741 if (!maybe_result->ToObject(&result)) return maybe_result;
742 }
743 }
744 return code;
745 }
746
747
ComputeKeyedStoreField(String * name,JSObject * receiver,int field_index,Map * transition,StrictModeFlag strict_mode)748 MaybeObject* StubCache::ComputeKeyedStoreField(String* name,
749 JSObject* receiver,
750 int field_index,
751 Map* transition,
752 StrictModeFlag strict_mode) {
753 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
754 Code::Flags flags = Code::ComputeMonomorphicFlags(
755 Code::KEYED_STORE_IC, type, strict_mode);
756 Object* code = receiver->map()->FindInCodeCache(name, flags);
757 if (code->IsUndefined()) {
758 KeyedStoreStubCompiler compiler(strict_mode);
759 { MaybeObject* maybe_code =
760 compiler.CompileStoreField(receiver, field_index, transition, name);
761 if (!maybe_code->ToObject(&code)) return maybe_code;
762 }
763 PROFILE(isolate(),
764 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
765 Code::cast(code), name));
766 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, name, Code::cast(code)));
767 Object* result;
768 { MaybeObject* maybe_result =
769 receiver->UpdateMapCodeCache(name, Code::cast(code));
770 if (!maybe_result->ToObject(&result)) return maybe_result;
771 }
772 }
773 return code;
774 }
775
776 #define CALL_LOGGER_TAG(kind, type) \
777 (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
778
ComputeCallConstant(int argc,InLoopFlag in_loop,Code::Kind kind,Code::ExtraICState extra_ic_state,String * name,Object * object,JSObject * holder,JSFunction * function)779 MaybeObject* StubCache::ComputeCallConstant(int argc,
780 InLoopFlag in_loop,
781 Code::Kind kind,
782 Code::ExtraICState extra_ic_state,
783 String* name,
784 Object* object,
785 JSObject* holder,
786 JSFunction* function) {
787 // Compute the check type and the map.
788 InlineCacheHolderFlag cache_holder =
789 IC::GetCodeCacheForObject(object, holder);
790 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
791
792 // Compute check type based on receiver/holder.
793 CheckType check = RECEIVER_MAP_CHECK;
794 if (object->IsString()) {
795 check = STRING_CHECK;
796 } else if (object->IsNumber()) {
797 check = NUMBER_CHECK;
798 } else if (object->IsBoolean()) {
799 check = BOOLEAN_CHECK;
800 }
801
802 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
803 CONSTANT_FUNCTION,
804 extra_ic_state,
805 cache_holder,
806 in_loop,
807 argc);
808 Object* code = map_holder->map()->FindInCodeCache(name, flags);
809 if (code->IsUndefined()) {
810 // If the function hasn't been compiled yet, we cannot do it now
811 // because it may cause GC. To avoid this issue, we return an
812 // internal error which will make sure we do not update any
813 // caches.
814 if (!function->is_compiled()) return Failure::InternalError();
815 // Compile the stub - only create stubs for fully compiled functions.
816 CallStubCompiler compiler(
817 argc, in_loop, kind, extra_ic_state, cache_holder);
818 { MaybeObject* maybe_code =
819 compiler.CompileCallConstant(object, holder, function, name, check);
820 if (!maybe_code->ToObject(&code)) return maybe_code;
821 }
822 Code::cast(code)->set_check_type(check);
823 ASSERT_EQ(flags, Code::cast(code)->flags());
824 PROFILE(isolate_,
825 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
826 Code::cast(code), name));
827 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
828 Object* result;
829 { MaybeObject* maybe_result =
830 map_holder->UpdateMapCodeCache(name, Code::cast(code));
831 if (!maybe_result->ToObject(&result)) return maybe_result;
832 }
833 }
834 return code;
835 }
836
837
ComputeCallField(int argc,InLoopFlag in_loop,Code::Kind kind,String * name,Object * object,JSObject * holder,int index)838 MaybeObject* StubCache::ComputeCallField(int argc,
839 InLoopFlag in_loop,
840 Code::Kind kind,
841 String* name,
842 Object* object,
843 JSObject* holder,
844 int index) {
845 // Compute the check type and the map.
846 InlineCacheHolderFlag cache_holder =
847 IC::GetCodeCacheForObject(object, holder);
848 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
849
850 // TODO(1233596): We cannot do receiver map check for non-JS objects
851 // because they may be represented as immediates without a
852 // map. Instead, we check against the map in the holder.
853 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
854 object = holder;
855 }
856
857 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
858 FIELD,
859 Code::kNoExtraICState,
860 cache_holder,
861 in_loop,
862 argc);
863 Object* code = map_holder->map()->FindInCodeCache(name, flags);
864 if (code->IsUndefined()) {
865 CallStubCompiler compiler(
866 argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
867 { MaybeObject* maybe_code =
868 compiler.CompileCallField(JSObject::cast(object),
869 holder,
870 index,
871 name);
872 if (!maybe_code->ToObject(&code)) return maybe_code;
873 }
874 ASSERT_EQ(flags, Code::cast(code)->flags());
875 PROFILE(isolate_,
876 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
877 Code::cast(code), name));
878 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
879 Object* result;
880 { MaybeObject* maybe_result =
881 map_holder->UpdateMapCodeCache(name, Code::cast(code));
882 if (!maybe_result->ToObject(&result)) return maybe_result;
883 }
884 }
885 return code;
886 }
887
888
ComputeCallInterceptor(int argc,Code::Kind kind,String * name,Object * object,JSObject * holder)889 MaybeObject* StubCache::ComputeCallInterceptor(int argc,
890 Code::Kind kind,
891 String* name,
892 Object* object,
893 JSObject* holder) {
894 // Compute the check type and the map.
895 InlineCacheHolderFlag cache_holder =
896 IC::GetCodeCacheForObject(object, holder);
897 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
898
899 // TODO(1233596): We cannot do receiver map check for non-JS objects
900 // because they may be represented as immediates without a
901 // map. Instead, we check against the map in the holder.
902 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
903 object = holder;
904 }
905
906 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
907 INTERCEPTOR,
908 Code::kNoExtraICState,
909 cache_holder,
910 NOT_IN_LOOP,
911 argc);
912 Object* code = map_holder->map()->FindInCodeCache(name, flags);
913 if (code->IsUndefined()) {
914 CallStubCompiler compiler(
915 argc, NOT_IN_LOOP, kind, Code::kNoExtraICState, cache_holder);
916 { MaybeObject* maybe_code =
917 compiler.CompileCallInterceptor(JSObject::cast(object), holder, name);
918 if (!maybe_code->ToObject(&code)) return maybe_code;
919 }
920 ASSERT_EQ(flags, Code::cast(code)->flags());
921 PROFILE(isolate(),
922 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
923 Code::cast(code), name));
924 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
925 Object* result;
926 { MaybeObject* maybe_result =
927 map_holder->UpdateMapCodeCache(name, Code::cast(code));
928 if (!maybe_result->ToObject(&result)) return maybe_result;
929 }
930 }
931 return code;
932 }
933
934
ComputeCallNormal(int argc,InLoopFlag in_loop,Code::Kind kind,String * name,JSObject * receiver)935 MaybeObject* StubCache::ComputeCallNormal(int argc,
936 InLoopFlag in_loop,
937 Code::Kind kind,
938 String* name,
939 JSObject* receiver) {
940 Object* code;
941 { MaybeObject* maybe_code = ComputeCallNormal(argc, in_loop, kind);
942 if (!maybe_code->ToObject(&code)) return maybe_code;
943 }
944 return code;
945 }
946
947
ComputeCallGlobal(int argc,InLoopFlag in_loop,Code::Kind kind,String * name,JSObject * receiver,GlobalObject * holder,JSGlobalPropertyCell * cell,JSFunction * function)948 MaybeObject* StubCache::ComputeCallGlobal(int argc,
949 InLoopFlag in_loop,
950 Code::Kind kind,
951 String* name,
952 JSObject* receiver,
953 GlobalObject* holder,
954 JSGlobalPropertyCell* cell,
955 JSFunction* function) {
956 InlineCacheHolderFlag cache_holder =
957 IC::GetCodeCacheForObject(receiver, holder);
958 JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder);
959 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
960 NORMAL,
961 Code::kNoExtraICState,
962 cache_holder,
963 in_loop,
964 argc);
965 Object* code = map_holder->map()->FindInCodeCache(name, flags);
966 if (code->IsUndefined()) {
967 // If the function hasn't been compiled yet, we cannot do it now
968 // because it may cause GC. To avoid this issue, we return an
969 // internal error which will make sure we do not update any
970 // caches.
971 if (!function->is_compiled()) return Failure::InternalError();
972 CallStubCompiler compiler(
973 argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
974 { MaybeObject* maybe_code =
975 compiler.CompileCallGlobal(receiver, holder, cell, function, name);
976 if (!maybe_code->ToObject(&code)) return maybe_code;
977 }
978 ASSERT_EQ(flags, Code::cast(code)->flags());
979 PROFILE(isolate(),
980 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
981 Code::cast(code), name));
982 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
983 Object* result;
984 { MaybeObject* maybe_result =
985 map_holder->UpdateMapCodeCache(name, Code::cast(code));
986 if (!maybe_result->ToObject(&result)) return maybe_result;
987 }
988 }
989 return code;
990 }
991
992
GetProbeValue(Isolate * isolate,Code::Flags flags)993 static Object* GetProbeValue(Isolate* isolate, Code::Flags flags) {
994 // Use raw_unchecked... so we don't get assert failures during GC.
995 NumberDictionary* dictionary =
996 isolate->heap()->raw_unchecked_non_monomorphic_cache();
997 int entry = dictionary->FindEntry(isolate, flags);
998 if (entry != -1) return dictionary->ValueAt(entry);
999 return isolate->heap()->raw_unchecked_undefined_value();
1000 }
1001
1002
ProbeCache(Isolate * isolate,Code::Flags flags)1003 MUST_USE_RESULT static MaybeObject* ProbeCache(Isolate* isolate,
1004 Code::Flags flags) {
1005 Heap* heap = isolate->heap();
1006 Object* probe = GetProbeValue(isolate, flags);
1007 if (probe != heap->undefined_value()) return probe;
1008 // Seed the cache with an undefined value to make sure that any
1009 // generated code object can always be inserted into the cache
1010 // without causing allocation failures.
1011 Object* result;
1012 { MaybeObject* maybe_result =
1013 heap->non_monomorphic_cache()->AtNumberPut(flags,
1014 heap->undefined_value());
1015 if (!maybe_result->ToObject(&result)) return maybe_result;
1016 }
1017 heap->public_set_non_monomorphic_cache(NumberDictionary::cast(result));
1018 return probe;
1019 }
1020
1021
FillCache(Isolate * isolate,MaybeObject * maybe_code)1022 static MaybeObject* FillCache(Isolate* isolate, MaybeObject* maybe_code) {
1023 Object* code;
1024 if (maybe_code->ToObject(&code)) {
1025 if (code->IsCode()) {
1026 Heap* heap = isolate->heap();
1027 int entry = heap->non_monomorphic_cache()->FindEntry(
1028 Code::cast(code)->flags());
1029 // The entry must be present see comment in ProbeCache.
1030 ASSERT(entry != -1);
1031 ASSERT(heap->non_monomorphic_cache()->ValueAt(entry) ==
1032 heap->undefined_value());
1033 heap->non_monomorphic_cache()->ValueAtPut(entry, code);
1034 CHECK(GetProbeValue(isolate, Code::cast(code)->flags()) == code);
1035 }
1036 }
1037 return maybe_code;
1038 }
1039
1040
FindCallInitialize(int argc,InLoopFlag in_loop,Code::Kind kind)1041 Code* StubCache::FindCallInitialize(int argc,
1042 InLoopFlag in_loop,
1043 Code::Kind kind) {
1044 Code::Flags flags = Code::ComputeFlags(kind,
1045 in_loop,
1046 UNINITIALIZED,
1047 Code::kNoExtraICState,
1048 NORMAL,
1049 argc);
1050 Object* result = ProbeCache(isolate(), flags)->ToObjectUnchecked();
1051 ASSERT(result != heap()->undefined_value());
1052 // This might be called during the marking phase of the collector
1053 // hence the unchecked cast.
1054 return reinterpret_cast<Code*>(result);
1055 }
1056
1057
ComputeCallInitialize(int argc,InLoopFlag in_loop,Code::Kind kind)1058 MaybeObject* StubCache::ComputeCallInitialize(int argc,
1059 InLoopFlag in_loop,
1060 Code::Kind kind) {
1061 Code::Flags flags = Code::ComputeFlags(kind,
1062 in_loop,
1063 UNINITIALIZED,
1064 Code::kNoExtraICState,
1065 NORMAL,
1066 argc);
1067 Object* probe;
1068 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1069 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1070 }
1071 if (!probe->IsUndefined()) return probe;
1072 StubCompiler compiler;
1073 return FillCache(isolate_, compiler.CompileCallInitialize(flags));
1074 }
1075
1076
ComputeCallInitialize(int argc,InLoopFlag in_loop)1077 Handle<Code> StubCache::ComputeCallInitialize(int argc, InLoopFlag in_loop) {
1078 if (in_loop == IN_LOOP) {
1079 // Force the creation of the corresponding stub outside loops,
1080 // because it may be used when clearing the ICs later - it is
1081 // possible for a series of IC transitions to lose the in-loop
1082 // information, and the IC clearing code can't generate a stub
1083 // that it needs so we need to ensure it is generated already.
1084 ComputeCallInitialize(argc, NOT_IN_LOOP);
1085 }
1086 CALL_HEAP_FUNCTION(isolate_,
1087 ComputeCallInitialize(argc, in_loop, Code::CALL_IC), Code);
1088 }
1089
1090
ComputeKeyedCallInitialize(int argc,InLoopFlag in_loop)1091 Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc,
1092 InLoopFlag in_loop) {
1093 if (in_loop == IN_LOOP) {
1094 // Force the creation of the corresponding stub outside loops,
1095 // because it may be used when clearing the ICs later - it is
1096 // possible for a series of IC transitions to lose the in-loop
1097 // information, and the IC clearing code can't generate a stub
1098 // that it needs so we need to ensure it is generated already.
1099 ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
1100 }
1101 CALL_HEAP_FUNCTION(
1102 isolate_,
1103 ComputeCallInitialize(argc, in_loop, Code::KEYED_CALL_IC), Code);
1104 }
1105
1106
ComputeCallPreMonomorphic(int argc,InLoopFlag in_loop,Code::Kind kind)1107 MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc,
1108 InLoopFlag in_loop,
1109 Code::Kind kind) {
1110 Code::Flags flags = Code::ComputeFlags(kind,
1111 in_loop,
1112 PREMONOMORPHIC,
1113 Code::kNoExtraICState,
1114 NORMAL,
1115 argc);
1116 Object* probe;
1117 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1118 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1119 }
1120 if (!probe->IsUndefined()) return probe;
1121 StubCompiler compiler;
1122 return FillCache(isolate_, compiler.CompileCallPreMonomorphic(flags));
1123 }
1124
1125
ComputeCallNormal(int argc,InLoopFlag in_loop,Code::Kind kind)1126 MaybeObject* StubCache::ComputeCallNormal(int argc,
1127 InLoopFlag in_loop,
1128 Code::Kind kind) {
1129 Code::Flags flags = Code::ComputeFlags(kind,
1130 in_loop,
1131 MONOMORPHIC,
1132 Code::kNoExtraICState,
1133 NORMAL,
1134 argc);
1135 Object* probe;
1136 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1137 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1138 }
1139 if (!probe->IsUndefined()) return probe;
1140 StubCompiler compiler;
1141 return FillCache(isolate_, compiler.CompileCallNormal(flags));
1142 }
1143
1144
ComputeCallMegamorphic(int argc,InLoopFlag in_loop,Code::Kind kind)1145 MaybeObject* StubCache::ComputeCallMegamorphic(int argc,
1146 InLoopFlag in_loop,
1147 Code::Kind kind) {
1148 Code::Flags flags = Code::ComputeFlags(kind,
1149 in_loop,
1150 MEGAMORPHIC,
1151 Code::kNoExtraICState,
1152 NORMAL,
1153 argc);
1154 Object* probe;
1155 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1156 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1157 }
1158 if (!probe->IsUndefined()) return probe;
1159 StubCompiler compiler;
1160 return FillCache(isolate_, compiler.CompileCallMegamorphic(flags));
1161 }
1162
1163
ComputeCallMiss(int argc,Code::Kind kind)1164 MaybeObject* StubCache::ComputeCallMiss(int argc, Code::Kind kind) {
1165 // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
1166 // and monomorphic stubs are not mixed up together in the stub cache.
1167 Code::Flags flags = Code::ComputeFlags(kind,
1168 NOT_IN_LOOP,
1169 MONOMORPHIC_PROTOTYPE_FAILURE,
1170 Code::kNoExtraICState,
1171 NORMAL,
1172 argc,
1173 OWN_MAP);
1174 Object* probe;
1175 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1176 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1177 }
1178 if (!probe->IsUndefined()) return probe;
1179 StubCompiler compiler;
1180 return FillCache(isolate_, compiler.CompileCallMiss(flags));
1181 }
1182
1183
1184 #ifdef ENABLE_DEBUGGER_SUPPORT
ComputeCallDebugBreak(int argc,Code::Kind kind)1185 MaybeObject* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) {
1186 Code::Flags flags = Code::ComputeFlags(kind,
1187 NOT_IN_LOOP,
1188 DEBUG_BREAK,
1189 Code::kNoExtraICState,
1190 NORMAL,
1191 argc);
1192 Object* probe;
1193 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1194 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1195 }
1196 if (!probe->IsUndefined()) return probe;
1197 StubCompiler compiler;
1198 return FillCache(isolate_, compiler.CompileCallDebugBreak(flags));
1199 }
1200
1201
ComputeCallDebugPrepareStepIn(int argc,Code::Kind kind)1202 MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(int argc,
1203 Code::Kind kind) {
1204 Code::Flags flags = Code::ComputeFlags(kind,
1205 NOT_IN_LOOP,
1206 DEBUG_PREPARE_STEP_IN,
1207 Code::kNoExtraICState,
1208 NORMAL,
1209 argc);
1210 Object* probe;
1211 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1212 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1213 }
1214 if (!probe->IsUndefined()) return probe;
1215 StubCompiler compiler;
1216 return FillCache(isolate_, compiler.CompileCallDebugPrepareStepIn(flags));
1217 }
1218 #endif
1219
1220
Clear()1221 void StubCache::Clear() {
1222 for (int i = 0; i < kPrimaryTableSize; i++) {
1223 primary_[i].key = heap()->empty_string();
1224 primary_[i].value = isolate_->builtins()->builtin(
1225 Builtins::kIllegal);
1226 }
1227 for (int j = 0; j < kSecondaryTableSize; j++) {
1228 secondary_[j].key = heap()->empty_string();
1229 secondary_[j].value = isolate_->builtins()->builtin(
1230 Builtins::kIllegal);
1231 }
1232 }
1233
1234
CollectMatchingMaps(ZoneMapList * types,String * name,Code::Flags flags)1235 void StubCache::CollectMatchingMaps(ZoneMapList* types,
1236 String* name,
1237 Code::Flags flags) {
1238 for (int i = 0; i < kPrimaryTableSize; i++) {
1239 if (primary_[i].key == name) {
1240 Map* map = primary_[i].value->FindFirstMap();
1241 // Map can be NULL, if the stub is constant function call
1242 // with a primitive receiver.
1243 if (map == NULL) continue;
1244
1245 int offset = PrimaryOffset(name, flags, map);
1246 if (entry(primary_, offset) == &primary_[i]) {
1247 types->Add(Handle<Map>(map));
1248 }
1249 }
1250 }
1251
1252 for (int i = 0; i < kSecondaryTableSize; i++) {
1253 if (secondary_[i].key == name) {
1254 Map* map = secondary_[i].value->FindFirstMap();
1255 // Map can be NULL, if the stub is constant function call
1256 // with a primitive receiver.
1257 if (map == NULL) continue;
1258
1259 // Lookup in primary table and skip duplicates.
1260 int primary_offset = PrimaryOffset(name, flags, map);
1261 Entry* primary_entry = entry(primary_, primary_offset);
1262 if (primary_entry->key == name) {
1263 Map* primary_map = primary_entry->value->FindFirstMap();
1264 if (map == primary_map) continue;
1265 }
1266
1267 // Lookup in secondary table and add matches.
1268 int offset = SecondaryOffset(name, flags, primary_offset);
1269 if (entry(secondary_, offset) == &secondary_[i]) {
1270 types->Add(Handle<Map>(map));
1271 }
1272 }
1273 }
1274 }
1275
1276
1277 // ------------------------------------------------------------------------
1278 // StubCompiler implementation.
1279
1280
RUNTIME_FUNCTION(MaybeObject *,LoadCallbackProperty)1281 RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty) {
1282 ASSERT(args[0]->IsJSObject());
1283 ASSERT(args[1]->IsJSObject());
1284 AccessorInfo* callback = AccessorInfo::cast(args[3]);
1285 Address getter_address = v8::ToCData<Address>(callback->getter());
1286 v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
1287 ASSERT(fun != NULL);
1288 v8::AccessorInfo info(&args[0]);
1289 HandleScope scope(isolate);
1290 v8::Handle<v8::Value> result;
1291 {
1292 // Leaving JavaScript.
1293 VMState state(isolate, EXTERNAL);
1294 ExternalCallbackScope call_scope(isolate, getter_address);
1295 result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
1296 }
1297 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1298 if (result.IsEmpty()) return HEAP->undefined_value();
1299 return *v8::Utils::OpenHandle(*result);
1300 }
1301
1302
RUNTIME_FUNCTION(MaybeObject *,StoreCallbackProperty)1303 RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
1304 JSObject* recv = JSObject::cast(args[0]);
1305 AccessorInfo* callback = AccessorInfo::cast(args[1]);
1306 Address setter_address = v8::ToCData<Address>(callback->setter());
1307 v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
1308 ASSERT(fun != NULL);
1309 Handle<String> name = args.at<String>(2);
1310 Handle<Object> value = args.at<Object>(3);
1311 HandleScope scope(isolate);
1312 LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
1313 CustomArguments custom_args(isolate, callback->data(), recv, recv);
1314 v8::AccessorInfo info(custom_args.end());
1315 {
1316 // Leaving JavaScript.
1317 VMState state(isolate, EXTERNAL);
1318 ExternalCallbackScope call_scope(isolate, setter_address);
1319 fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
1320 }
1321 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1322 return *value;
1323 }
1324
1325
1326 static const int kAccessorInfoOffsetInInterceptorArgs = 2;
1327
1328
1329 /**
1330 * Attempts to load a property with an interceptor (which must be present),
1331 * but doesn't search the prototype chain.
1332 *
1333 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
1334 * provide any value for the given name.
1335 */
RUNTIME_FUNCTION(MaybeObject *,LoadPropertyWithInterceptorOnly)1336 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
1337 Handle<String> name_handle = args.at<String>(0);
1338 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
1339 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1340 ASSERT(args[2]->IsJSObject()); // Receiver.
1341 ASSERT(args[3]->IsJSObject()); // Holder.
1342 ASSERT(args.length() == 5); // Last arg is data object.
1343
1344 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1345 v8::NamedPropertyGetter getter =
1346 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1347 ASSERT(getter != NULL);
1348
1349 {
1350 // Use the interceptor getter.
1351 v8::AccessorInfo info(args.arguments() -
1352 kAccessorInfoOffsetInInterceptorArgs);
1353 HandleScope scope(isolate);
1354 v8::Handle<v8::Value> r;
1355 {
1356 // Leaving JavaScript.
1357 VMState state(isolate, EXTERNAL);
1358 r = getter(v8::Utils::ToLocal(name_handle), info);
1359 }
1360 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1361 if (!r.IsEmpty()) {
1362 return *v8::Utils::OpenHandle(*r);
1363 }
1364 }
1365
1366 return isolate->heap()->no_interceptor_result_sentinel();
1367 }
1368
1369
ThrowReferenceError(String * name)1370 static MaybeObject* ThrowReferenceError(String* name) {
1371 // If the load is non-contextual, just return the undefined result.
1372 // Note that both keyed and non-keyed loads may end up here, so we
1373 // can't use either LoadIC or KeyedLoadIC constructors.
1374 IC ic(IC::NO_EXTRA_FRAME, Isolate::Current());
1375 ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
1376 if (!ic.SlowIsContextual()) return HEAP->undefined_value();
1377
1378 // Throw a reference error.
1379 HandleScope scope;
1380 Handle<String> name_handle(name);
1381 Handle<Object> error =
1382 FACTORY->NewReferenceError("not_defined",
1383 HandleVector(&name_handle, 1));
1384 return Isolate::Current()->Throw(*error);
1385 }
1386
1387
LoadWithInterceptor(Arguments * args,PropertyAttributes * attrs)1388 static MaybeObject* LoadWithInterceptor(Arguments* args,
1389 PropertyAttributes* attrs) {
1390 Handle<String> name_handle = args->at<String>(0);
1391 Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
1392 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1393 Handle<JSObject> receiver_handle = args->at<JSObject>(2);
1394 Handle<JSObject> holder_handle = args->at<JSObject>(3);
1395 ASSERT(args->length() == 5); // Last arg is data object.
1396
1397 Isolate* isolate = receiver_handle->GetIsolate();
1398
1399 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1400 v8::NamedPropertyGetter getter =
1401 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1402 ASSERT(getter != NULL);
1403
1404 {
1405 // Use the interceptor getter.
1406 v8::AccessorInfo info(args->arguments() -
1407 kAccessorInfoOffsetInInterceptorArgs);
1408 HandleScope scope(isolate);
1409 v8::Handle<v8::Value> r;
1410 {
1411 // Leaving JavaScript.
1412 VMState state(isolate, EXTERNAL);
1413 r = getter(v8::Utils::ToLocal(name_handle), info);
1414 }
1415 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1416 if (!r.IsEmpty()) {
1417 *attrs = NONE;
1418 return *v8::Utils::OpenHandle(*r);
1419 }
1420 }
1421
1422 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
1423 *receiver_handle,
1424 *name_handle,
1425 attrs);
1426 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1427 return result;
1428 }
1429
1430
1431 /**
1432 * Loads a property with an interceptor performing post interceptor
1433 * lookup if interceptor failed.
1434 */
RUNTIME_FUNCTION(MaybeObject *,LoadPropertyWithInterceptorForLoad)1435 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
1436 PropertyAttributes attr = NONE;
1437 Object* result;
1438 { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
1439 if (!maybe_result->ToObject(&result)) return maybe_result;
1440 }
1441
1442 // If the property is present, return it.
1443 if (attr != ABSENT) return result;
1444 return ThrowReferenceError(String::cast(args[0]));
1445 }
1446
1447
RUNTIME_FUNCTION(MaybeObject *,LoadPropertyWithInterceptorForCall)1448 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
1449 PropertyAttributes attr;
1450 MaybeObject* result = LoadWithInterceptor(&args, &attr);
1451 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1452 // This is call IC. In this case, we simply return the undefined result which
1453 // will lead to an exception when trying to invoke the result as a
1454 // function.
1455 return result;
1456 }
1457
1458
RUNTIME_FUNCTION(MaybeObject *,StoreInterceptorProperty)1459 RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
1460 ASSERT(args.length() == 4);
1461 JSObject* recv = JSObject::cast(args[0]);
1462 String* name = String::cast(args[1]);
1463 Object* value = args[2];
1464 StrictModeFlag strict_mode =
1465 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1466 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
1467 ASSERT(recv->HasNamedInterceptor());
1468 PropertyAttributes attr = NONE;
1469 MaybeObject* result = recv->SetPropertyWithInterceptor(
1470 name, value, attr, strict_mode);
1471 return result;
1472 }
1473
1474
RUNTIME_FUNCTION(MaybeObject *,KeyedLoadPropertyWithInterceptor)1475 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
1476 JSObject* receiver = JSObject::cast(args[0]);
1477 ASSERT(Smi::cast(args[1])->value() >= 0);
1478 uint32_t index = Smi::cast(args[1])->value();
1479 return receiver->GetElementWithInterceptor(receiver, index);
1480 }
1481
1482
CompileCallInitialize(Code::Flags flags)1483 MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) {
1484 HandleScope scope(isolate());
1485 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1486 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1487 if (kind == Code::CALL_IC) {
1488 CallIC::GenerateInitialize(masm(), argc);
1489 } else {
1490 KeyedCallIC::GenerateInitialize(masm(), argc);
1491 }
1492 Object* result;
1493 { MaybeObject* maybe_result =
1494 GetCodeWithFlags(flags, "CompileCallInitialize");
1495 if (!maybe_result->ToObject(&result)) return maybe_result;
1496 }
1497 isolate()->counters()->call_initialize_stubs()->Increment();
1498 Code* code = Code::cast(result);
1499 USE(code);
1500 PROFILE(isolate(),
1501 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
1502 code, code->arguments_count()));
1503 GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, Code::cast(code)));
1504 return result;
1505 }
1506
1507
CompileCallPreMonomorphic(Code::Flags flags)1508 MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
1509 HandleScope scope(isolate());
1510 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1511 // The code of the PreMonomorphic stub is the same as the code
1512 // of the Initialized stub. They just differ on the code object flags.
1513 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1514 if (kind == Code::CALL_IC) {
1515 CallIC::GenerateInitialize(masm(), argc);
1516 } else {
1517 KeyedCallIC::GenerateInitialize(masm(), argc);
1518 }
1519 Object* result;
1520 { MaybeObject* maybe_result =
1521 GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1522 if (!maybe_result->ToObject(&result)) return maybe_result;
1523 }
1524 isolate()->counters()->call_premonomorphic_stubs()->Increment();
1525 Code* code = Code::cast(result);
1526 USE(code);
1527 PROFILE(isolate(),
1528 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
1529 code, code->arguments_count()));
1530 GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, Code::cast(code)));
1531 return result;
1532 }
1533
1534
CompileCallNormal(Code::Flags flags)1535 MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
1536 HandleScope scope(isolate());
1537 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1538 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1539 if (kind == Code::CALL_IC) {
1540 CallIC::GenerateNormal(masm(), argc);
1541 } else {
1542 KeyedCallIC::GenerateNormal(masm(), argc);
1543 }
1544 Object* result;
1545 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallNormal");
1546 if (!maybe_result->ToObject(&result)) return maybe_result;
1547 }
1548 isolate()->counters()->call_normal_stubs()->Increment();
1549 Code* code = Code::cast(result);
1550 USE(code);
1551 PROFILE(isolate(),
1552 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
1553 code, code->arguments_count()));
1554 GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, Code::cast(code)));
1555 return result;
1556 }
1557
1558
CompileCallMegamorphic(Code::Flags flags)1559 MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
1560 HandleScope scope(isolate());
1561 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1562 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1563 if (kind == Code::CALL_IC) {
1564 CallIC::GenerateMegamorphic(masm(), argc);
1565 } else {
1566 KeyedCallIC::GenerateMegamorphic(masm(), argc);
1567 }
1568 Object* result;
1569 { MaybeObject* maybe_result =
1570 GetCodeWithFlags(flags, "CompileCallMegamorphic");
1571 if (!maybe_result->ToObject(&result)) return maybe_result;
1572 }
1573 isolate()->counters()->call_megamorphic_stubs()->Increment();
1574 Code* code = Code::cast(result);
1575 USE(code);
1576 PROFILE(isolate(),
1577 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
1578 code, code->arguments_count()));
1579 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code)));
1580 return result;
1581 }
1582
1583
CompileCallMiss(Code::Flags flags)1584 MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
1585 HandleScope scope(isolate());
1586 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1587 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1588 if (kind == Code::CALL_IC) {
1589 CallIC::GenerateMiss(masm(), argc);
1590 } else {
1591 KeyedCallIC::GenerateMiss(masm(), argc);
1592 }
1593 Object* result;
1594 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallMiss");
1595 if (!maybe_result->ToObject(&result)) return maybe_result;
1596 }
1597 isolate()->counters()->call_megamorphic_stubs()->Increment();
1598 Code* code = Code::cast(result);
1599 USE(code);
1600 PROFILE(isolate(),
1601 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
1602 code, code->arguments_count()));
1603 GDBJIT(AddCode(GDBJITInterface::CALL_MISS, Code::cast(code)));
1604 return result;
1605 }
1606
1607
1608 #ifdef ENABLE_DEBUGGER_SUPPORT
CompileCallDebugBreak(Code::Flags flags)1609 MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
1610 HandleScope scope(isolate());
1611 Debug::GenerateCallICDebugBreak(masm());
1612 Object* result;
1613 { MaybeObject* maybe_result =
1614 GetCodeWithFlags(flags, "CompileCallDebugBreak");
1615 if (!maybe_result->ToObject(&result)) return maybe_result;
1616 }
1617 Code* code = Code::cast(result);
1618 USE(code);
1619 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1620 USE(kind);
1621 PROFILE(isolate(),
1622 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
1623 code, code->arguments_count()));
1624 return result;
1625 }
1626
1627
CompileCallDebugPrepareStepIn(Code::Flags flags)1628 MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
1629 HandleScope scope(isolate());
1630 // Use the same code for the the step in preparations as we do for
1631 // the miss case.
1632 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1633 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1634 if (kind == Code::CALL_IC) {
1635 CallIC::GenerateMiss(masm(), argc);
1636 } else {
1637 KeyedCallIC::GenerateMiss(masm(), argc);
1638 }
1639 Object* result;
1640 { MaybeObject* maybe_result =
1641 GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1642 if (!maybe_result->ToObject(&result)) return maybe_result;
1643 }
1644 Code* code = Code::cast(result);
1645 USE(code);
1646 PROFILE(isolate(),
1647 CodeCreateEvent(
1648 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1649 code,
1650 code->arguments_count()));
1651 return result;
1652 }
1653 #endif
1654
1655 #undef CALL_LOGGER_TAG
1656
GetCodeWithFlags(Code::Flags flags,const char * name)1657 MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags,
1658 const char* name) {
1659 // Check for allocation failures during stub compilation.
1660 if (failure_->IsFailure()) return failure_;
1661
1662 // Create code object in the heap.
1663 CodeDesc desc;
1664 masm_.GetCode(&desc);
1665 MaybeObject* result = heap()->CreateCode(desc, flags, masm_.CodeObject());
1666 #ifdef ENABLE_DISASSEMBLER
1667 if (FLAG_print_code_stubs && !result->IsFailure()) {
1668 Code::cast(result->ToObjectUnchecked())->Disassemble(name);
1669 }
1670 #endif
1671 return result;
1672 }
1673
1674
GetCodeWithFlags(Code::Flags flags,String * name)1675 MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
1676 if (FLAG_print_code_stubs && (name != NULL)) {
1677 return GetCodeWithFlags(flags, *name->ToCString());
1678 }
1679 return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1680 }
1681
1682
LookupPostInterceptor(JSObject * holder,String * name,LookupResult * lookup)1683 void StubCompiler::LookupPostInterceptor(JSObject* holder,
1684 String* name,
1685 LookupResult* lookup) {
1686 holder->LocalLookupRealNamedProperty(name, lookup);
1687 if (!lookup->IsProperty()) {
1688 lookup->NotFound();
1689 Object* proto = holder->GetPrototype();
1690 if (!proto->IsNull()) {
1691 proto->Lookup(name, lookup);
1692 }
1693 }
1694 }
1695
1696
1697
GetCode(PropertyType type,String * name)1698 MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) {
1699 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
1700 MaybeObject* result = GetCodeWithFlags(flags, name);
1701 if (!result->IsFailure()) {
1702 PROFILE(isolate(),
1703 CodeCreateEvent(Logger::LOAD_IC_TAG,
1704 Code::cast(result->ToObjectUnchecked()),
1705 name));
1706 GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1707 name,
1708 Code::cast(result->ToObjectUnchecked())));
1709 }
1710 return result;
1711 }
1712
1713
GetCode(PropertyType type,String * name)1714 MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
1715 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
1716 MaybeObject* result = GetCodeWithFlags(flags, name);
1717 if (!result->IsFailure()) {
1718 PROFILE(isolate(),
1719 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
1720 Code::cast(result->ToObjectUnchecked()),
1721 name));
1722 GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1723 name,
1724 Code::cast(result->ToObjectUnchecked())));
1725 }
1726 return result;
1727 }
1728
1729
GetCode(PropertyType type,String * name)1730 MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
1731 Code::Flags flags = Code::ComputeMonomorphicFlags(
1732 Code::STORE_IC, type, strict_mode_);
1733 MaybeObject* result = GetCodeWithFlags(flags, name);
1734 if (!result->IsFailure()) {
1735 PROFILE(isolate(),
1736 CodeCreateEvent(Logger::STORE_IC_TAG,
1737 Code::cast(result->ToObjectUnchecked()),
1738 name));
1739 GDBJIT(AddCode(GDBJITInterface::STORE_IC,
1740 name,
1741 Code::cast(result->ToObjectUnchecked())));
1742 }
1743 return result;
1744 }
1745
1746
GetCode(PropertyType type,String * name)1747 MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
1748 Code::Flags flags = Code::ComputeMonomorphicFlags(
1749 Code::KEYED_STORE_IC, type, strict_mode_);
1750 MaybeObject* result = GetCodeWithFlags(flags, name);
1751 if (!result->IsFailure()) {
1752 PROFILE(isolate(),
1753 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
1754 Code::cast(result->ToObjectUnchecked()),
1755 name));
1756 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC,
1757 name,
1758 Code::cast(result->ToObjectUnchecked())));
1759 }
1760 return result;
1761 }
1762
1763
CallStubCompiler(int argc,InLoopFlag in_loop,Code::Kind kind,Code::ExtraICState extra_ic_state,InlineCacheHolderFlag cache_holder)1764 CallStubCompiler::CallStubCompiler(int argc,
1765 InLoopFlag in_loop,
1766 Code::Kind kind,
1767 Code::ExtraICState extra_ic_state,
1768 InlineCacheHolderFlag cache_holder)
1769 : arguments_(argc),
1770 in_loop_(in_loop),
1771 kind_(kind),
1772 extra_ic_state_(extra_ic_state),
1773 cache_holder_(cache_holder) {
1774 }
1775
1776
HasCustomCallGenerator(JSFunction * function)1777 bool CallStubCompiler::HasCustomCallGenerator(JSFunction* function) {
1778 SharedFunctionInfo* info = function->shared();
1779 if (info->HasBuiltinFunctionId()) {
1780 BuiltinFunctionId id = info->builtin_function_id();
1781 #define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
1782 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1783 #undef CALL_GENERATOR_CASE
1784 }
1785 CallOptimization optimization(function);
1786 if (optimization.is_simple_api_call()) {
1787 return true;
1788 }
1789 return false;
1790 }
1791
1792
CompileCustomCall(Object * object,JSObject * holder,JSGlobalPropertyCell * cell,JSFunction * function,String * fname)1793 MaybeObject* CallStubCompiler::CompileCustomCall(Object* object,
1794 JSObject* holder,
1795 JSGlobalPropertyCell* cell,
1796 JSFunction* function,
1797 String* fname) {
1798 ASSERT(HasCustomCallGenerator(function));
1799
1800 SharedFunctionInfo* info = function->shared();
1801 if (info->HasBuiltinFunctionId()) {
1802 BuiltinFunctionId id = info->builtin_function_id();
1803 #define CALL_GENERATOR_CASE(name) \
1804 if (id == k##name) { \
1805 return CallStubCompiler::Compile##name##Call(object, \
1806 holder, \
1807 cell, \
1808 function, \
1809 fname); \
1810 }
1811 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1812 #undef CALL_GENERATOR_CASE
1813 }
1814 CallOptimization optimization(function);
1815 ASSERT(optimization.is_simple_api_call());
1816 return CompileFastApiCall(optimization,
1817 object,
1818 holder,
1819 cell,
1820 function,
1821 fname);
1822 }
1823
1824
GetCode(PropertyType type,String * name)1825 MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
1826 int argc = arguments_.immediate();
1827 Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
1828 type,
1829 extra_ic_state_,
1830 cache_holder_,
1831 in_loop_,
1832 argc);
1833 return GetCodeWithFlags(flags, name);
1834 }
1835
1836
GetCode(JSFunction * function)1837 MaybeObject* CallStubCompiler::GetCode(JSFunction* function) {
1838 String* function_name = NULL;
1839 if (function->shared()->name()->IsString()) {
1840 function_name = String::cast(function->shared()->name());
1841 }
1842 return GetCode(CONSTANT_FUNCTION, function_name);
1843 }
1844
1845
GetCode()1846 MaybeObject* ConstructStubCompiler::GetCode() {
1847 Code::Flags flags = Code::ComputeFlags(Code::STUB);
1848 Object* result;
1849 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ConstructStub");
1850 if (!maybe_result->ToObject(&result)) return maybe_result;
1851 }
1852 Code* code = Code::cast(result);
1853 USE(code);
1854 PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
1855 GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", Code::cast(code)));
1856 return result;
1857 }
1858
1859
CallOptimization(LookupResult * lookup)1860 CallOptimization::CallOptimization(LookupResult* lookup) {
1861 if (!lookup->IsProperty() || !lookup->IsCacheable() ||
1862 lookup->type() != CONSTANT_FUNCTION) {
1863 Initialize(NULL);
1864 } else {
1865 // We only optimize constant function calls.
1866 Initialize(lookup->GetConstantFunction());
1867 }
1868 }
1869
CallOptimization(JSFunction * function)1870 CallOptimization::CallOptimization(JSFunction* function) {
1871 Initialize(function);
1872 }
1873
1874
GetPrototypeDepthOfExpectedType(JSObject * object,JSObject * holder) const1875 int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object,
1876 JSObject* holder) const {
1877 ASSERT(is_simple_api_call_);
1878 if (expected_receiver_type_ == NULL) return 0;
1879 int depth = 0;
1880 while (object != holder) {
1881 if (object->IsInstanceOf(expected_receiver_type_)) return depth;
1882 object = JSObject::cast(object->GetPrototype());
1883 ++depth;
1884 }
1885 if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
1886 return kInvalidProtoDepth;
1887 }
1888
1889
Initialize(JSFunction * function)1890 void CallOptimization::Initialize(JSFunction* function) {
1891 constant_function_ = NULL;
1892 is_simple_api_call_ = false;
1893 expected_receiver_type_ = NULL;
1894 api_call_info_ = NULL;
1895
1896 if (function == NULL || !function->is_compiled()) return;
1897
1898 constant_function_ = function;
1899 AnalyzePossibleApiFunction(function);
1900 }
1901
1902
AnalyzePossibleApiFunction(JSFunction * function)1903 void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
1904 SharedFunctionInfo* sfi = function->shared();
1905 if (!sfi->IsApiFunction()) return;
1906 FunctionTemplateInfo* info = sfi->get_api_func_data();
1907
1908 // Require a C++ callback.
1909 if (info->call_code()->IsUndefined()) return;
1910 api_call_info_ = CallHandlerInfo::cast(info->call_code());
1911
1912 // Accept signatures that either have no restrictions at all or
1913 // only have restrictions on the receiver.
1914 if (!info->signature()->IsUndefined()) {
1915 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1916 if (!signature->args()->IsUndefined()) return;
1917 if (!signature->receiver()->IsUndefined()) {
1918 expected_receiver_type_ =
1919 FunctionTemplateInfo::cast(signature->receiver());
1920 }
1921 }
1922
1923 is_simple_api_call_ = true;
1924 }
1925
1926
GetCode(Code::Flags flags)1927 MaybeObject* ExternalArrayStubCompiler::GetCode(Code::Flags flags) {
1928 Object* result;
1929 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ExternalArrayStub");
1930 if (!maybe_result->ToObject(&result)) return maybe_result;
1931 }
1932 Code* code = Code::cast(result);
1933 USE(code);
1934 PROFILE(isolate(),
1935 CodeCreateEvent(Logger::STUB_TAG, code, "ExternalArrayStub"));
1936 return result;
1937 }
1938
1939
1940 } } // namespace v8::internal
1941