Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(74)

Side by Side Diff: src/stub-cache.cc

Issue 483683005: Move IC code into a subdir and move ic-compilation related code from stub-cache into ic-compiler (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Fix BUILD.gn Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/stub-cache.h ('k') | src/type-info.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #include "src/api.h"
8 #include "src/arguments.h"
9 #include "src/ast.h"
10 #include "src/code-stubs.h"
11 #include "src/cpu-profiler.h"
12 #include "src/gdb-jit.h"
13 #include "src/ic-inl.h"
14 #include "src/stub-cache.h"
15 #include "src/type-info.h"
16 #include "src/vm-state-inl.h"
17
18 namespace v8 {
19 namespace internal {
20
21 // -----------------------------------------------------------------------
22 // StubCache implementation.
23
24
25 StubCache::StubCache(Isolate* isolate)
26 : isolate_(isolate) { }
27
28
29 void StubCache::Initialize() {
30 DCHECK(IsPowerOf2(kPrimaryTableSize));
31 DCHECK(IsPowerOf2(kSecondaryTableSize));
32 Clear();
33 }
34
35
36 static Code::Flags CommonStubCacheChecks(Name* name, Map* map,
37 Code::Flags flags) {
38 flags = Code::RemoveTypeAndHolderFromFlags(flags);
39
40 // Validate that the name does not move on scavenge, and that we
41 // can use identity checks instead of structural equality checks.
42 DCHECK(!name->GetHeap()->InNewSpace(name));
43 DCHECK(name->IsUniqueName());
44
45 // The state bits are not important to the hash function because the stub
46 // cache only contains handlers. Make sure that the bits are the least
47 // significant so they will be the ones masked out.
48 DCHECK_EQ(Code::HANDLER, Code::ExtractKindFromFlags(flags));
49 STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
50
51 // Make sure that the code type and cache holder are not included in the hash.
52 DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
53 DCHECK(Code::ExtractCacheHolderFromFlags(flags) == 0);
54
55 return flags;
56 }
57
58
59 Code* StubCache::Set(Name* name, Map* map, Code* code) {
60 Code::Flags flags = CommonStubCacheChecks(name, map, code->flags());
61
62 // Compute the primary entry.
63 int primary_offset = PrimaryOffset(name, flags, map);
64 Entry* primary = entry(primary_, primary_offset);
65 Code* old_code = primary->value;
66
67 // If the primary entry has useful data in it, we retire it to the
68 // secondary cache before overwriting it.
69 if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) {
70 Map* old_map = primary->map;
71 Code::Flags old_flags =
72 Code::RemoveTypeAndHolderFromFlags(old_code->flags());
73 int seed = PrimaryOffset(primary->key, old_flags, old_map);
74 int secondary_offset = SecondaryOffset(primary->key, old_flags, seed);
75 Entry* secondary = entry(secondary_, secondary_offset);
76 *secondary = *primary;
77 }
78
79 // Update primary cache.
80 primary->key = name;
81 primary->value = code;
82 primary->map = map;
83 isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
84 return code;
85 }
86
87
88 Code* StubCache::Get(Name* name, Map* map, Code::Flags flags) {
89 flags = CommonStubCacheChecks(name, map, flags);
90 int primary_offset = PrimaryOffset(name, flags, map);
91 Entry* primary = entry(primary_, primary_offset);
92 if (primary->key == name && primary->map == map) {
93 return primary->value;
94 }
95 int secondary_offset = SecondaryOffset(name, flags, primary_offset);
96 Entry* secondary = entry(secondary_, secondary_offset);
97 if (secondary->key == name && secondary->map == map) {
98 return secondary->value;
99 }
100 return NULL;
101 }
102
103
104 Handle<Code> PropertyICCompiler::Find(Handle<Name> name,
105 Handle<Map> stub_holder, Code::Kind kind,
106 ExtraICState extra_state,
107 CacheHolderFlag cache_holder) {
108 Code::Flags flags = Code::ComputeMonomorphicFlags(
109 kind, extra_state, cache_holder);
110 Object* probe = stub_holder->FindInCodeCache(*name, flags);
111 if (probe->IsCode()) return handle(Code::cast(probe));
112 return Handle<Code>::null();
113 }
114
115
116 Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
117 Handle<Map> stub_holder,
118 Code::Kind kind,
119 CacheHolderFlag cache_holder,
120 Code::StubType type) {
121 Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder);
122 Object* probe = stub_holder->FindInCodeCache(*name, flags);
123 if (probe->IsCode()) return handle(Code::cast(probe));
124 return Handle<Code>::null();
125 }
126
127
128 Handle<Code> PropertyICCompiler::ComputeMonomorphic(
129 Code::Kind kind, Handle<Name> name, Handle<HeapType> type,
130 Handle<Code> handler, ExtraICState extra_ic_state) {
131 Isolate* isolate = name->GetIsolate();
132 if (handler.is_identical_to(isolate->builtins()->LoadIC_Normal()) ||
133 handler.is_identical_to(isolate->builtins()->StoreIC_Normal())) {
134 name = isolate->factory()->normal_ic_symbol();
135 }
136
137 CacheHolderFlag flag;
138 Handle<Map> stub_holder = IC::GetICCacheHolder(*type, isolate, &flag);
139
140 Handle<Code> ic;
141 // There are multiple string maps that all use the same prototype. That
142 // prototype cannot hold multiple handlers, one for each of the string maps,
143 // for a single name. Hence, turn off caching of the IC.
144 bool can_be_cached = !type->Is(HeapType::String());
145 if (can_be_cached) {
146 ic = Find(name, stub_holder, kind, extra_ic_state, flag);
147 if (!ic.is_null()) return ic;
148 }
149
150 #ifdef DEBUG
151 if (kind == Code::KEYED_STORE_IC) {
152 DCHECK(STANDARD_STORE ==
153 KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state));
154 }
155 #endif
156
157 PropertyICCompiler ic_compiler(isolate, kind, extra_ic_state, flag);
158 ic = ic_compiler.CompileMonomorphic(type, handler, name, PROPERTY);
159
160 if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic);
161 return ic;
162 }
163
164
165 Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
166 Handle<Name> name, Handle<HeapType> type) {
167 Isolate* isolate = name->GetIsolate();
168 Handle<Map> receiver_map = IC::TypeToMap(*type, isolate);
169 if (receiver_map->prototype()->IsNull()) {
170 // TODO(jkummerow/verwaest): If there is no prototype and the property
171 // is nonexistent, introduce a builtin to handle this (fast properties
172 // -> return undefined, dictionary properties -> do negative lookup).
173 return Handle<Code>();
174 }
175 CacheHolderFlag flag;
176 Handle<Map> stub_holder_map =
177 IC::GetHandlerCacheHolder(*type, false, isolate, &flag);
178
179 // If no dictionary mode objects are present in the prototype chain, the load
180 // nonexistent IC stub can be shared for all names for a given map and we use
181 // the empty string for the map cache in that case. If there are dictionary
182 // mode objects involved, we need to do negative lookups in the stub and
183 // therefore the stub will be specific to the name.
184 Handle<Name> cache_name =
185 receiver_map->is_dictionary_map()
186 ? name
187 : Handle<Name>::cast(isolate->factory()->nonexistent_symbol());
188 Handle<Map> current_map = stub_holder_map;
189 Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
190 while (true) {
191 if (current_map->is_dictionary_map()) cache_name = name;
192 if (current_map->prototype()->IsNull()) break;
193 last = handle(JSObject::cast(current_map->prototype()));
194 current_map = handle(last->map());
195 }
196 // Compile the stub that is either shared for all names or
197 // name specific if there are global objects involved.
198 Handle<Code> handler = PropertyHandlerCompiler::Find(
199 cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST);
200 if (!handler.is_null()) return handler;
201
202 NamedLoadHandlerCompiler compiler(isolate, type, last, flag);
203 handler = compiler.CompileLoadNonexistent(cache_name);
204 Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
205 return handler;
206 }
207
208
209 Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic(
210 Handle<Map> receiver_map) {
211 Isolate* isolate = receiver_map->GetIsolate();
212 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC);
213 Handle<Name> name = isolate->factory()->KeyedLoadMonomorphic_string();
214
215 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate);
216 if (probe->IsCode()) return Handle<Code>::cast(probe);
217
218 ElementsKind elements_kind = receiver_map->elements_kind();
219 Handle<Code> stub;
220 if (receiver_map->has_fast_elements() ||
221 receiver_map->has_external_array_elements() ||
222 receiver_map->has_fixed_typed_array_elements()) {
223 stub = LoadFastElementStub(isolate,
224 receiver_map->instance_type() == JS_ARRAY_TYPE,
225 elements_kind).GetCode();
226 } else {
227 stub = FLAG_compiled_keyed_dictionary_loads
228 ? LoadDictionaryElementStub(isolate).GetCode()
229 : LoadDictionaryElementPlatformStub(isolate).GetCode();
230 }
231 PropertyICCompiler compiler(isolate, Code::KEYED_LOAD_IC);
232 Handle<Code> code =
233 compiler.CompileMonomorphic(HeapType::Class(receiver_map, isolate), stub,
234 isolate->factory()->empty_string(), ELEMENT);
235
236 Map::UpdateCodeCache(receiver_map, name, code);
237 return code;
238 }
239
240
241 Handle<Code> PropertyICCompiler::ComputeKeyedStoreMonomorphic(
242 Handle<Map> receiver_map, StrictMode strict_mode,
243 KeyedAccessStoreMode store_mode) {
244 Isolate* isolate = receiver_map->GetIsolate();
245 ExtraICState extra_state =
246 KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode);
247 Code::Flags flags =
248 Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, extra_state);
249
250 DCHECK(store_mode == STANDARD_STORE ||
251 store_mode == STORE_AND_GROW_NO_TRANSITION ||
252 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
253 store_mode == STORE_NO_TRANSITION_HANDLE_COW);
254
255 Handle<String> name = isolate->factory()->KeyedStoreMonomorphic_string();
256 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate);
257 if (probe->IsCode()) return Handle<Code>::cast(probe);
258
259 PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
260 Handle<Code> code =
261 compiler.CompileKeyedStoreMonomorphic(receiver_map, store_mode);
262
263 Map::UpdateCodeCache(receiver_map, name, code);
264 DCHECK(KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state())
265 == store_mode);
266 return code;
267 }
268
269
270 #define CALL_LOGGER_TAG(kind, type) (Logger::KEYED_##type)
271
272 static void FillCache(Isolate* isolate, Handle<Code> code) {
273 Handle<UnseededNumberDictionary> dictionary =
274 UnseededNumberDictionary::Set(isolate->factory()->non_monomorphic_cache(),
275 code->flags(),
276 code);
277 isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
278 }
279
280
281 Code* PropertyICCompiler::FindPreMonomorphic(Isolate* isolate, Code::Kind kind,
282 ExtraICState state) {
283 Code::Flags flags = Code::ComputeFlags(kind, PREMONOMORPHIC, state);
284 UnseededNumberDictionary* dictionary =
285 isolate->heap()->non_monomorphic_cache();
286 int entry = dictionary->FindEntry(isolate, flags);
287 DCHECK(entry != -1);
288 Object* code = dictionary->ValueAt(entry);
289 // This might be called during the marking phase of the collector
290 // hence the unchecked cast.
291 return reinterpret_cast<Code*>(code);
292 }
293
294
295 Handle<Code> PropertyICCompiler::ComputeLoad(Isolate* isolate,
296 InlineCacheState ic_state,
297 ExtraICState extra_state) {
298 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, ic_state, extra_state);
299 Handle<UnseededNumberDictionary> cache =
300 isolate->factory()->non_monomorphic_cache();
301 int entry = cache->FindEntry(isolate, flags);
302 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
303
304 PropertyICCompiler compiler(isolate, Code::LOAD_IC);
305 Handle<Code> code;
306 if (ic_state == UNINITIALIZED) {
307 code = compiler.CompileLoadInitialize(flags);
308 } else if (ic_state == PREMONOMORPHIC) {
309 code = compiler.CompileLoadPreMonomorphic(flags);
310 } else if (ic_state == MEGAMORPHIC) {
311 code = compiler.CompileLoadMegamorphic(flags);
312 } else {
313 UNREACHABLE();
314 }
315 FillCache(isolate, code);
316 return code;
317 }
318
319
320 Handle<Code> PropertyICCompiler::ComputeStore(Isolate* isolate,
321 InlineCacheState ic_state,
322 ExtraICState extra_state) {
323 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, ic_state, extra_state);
324 Handle<UnseededNumberDictionary> cache =
325 isolate->factory()->non_monomorphic_cache();
326 int entry = cache->FindEntry(isolate, flags);
327 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
328
329 PropertyICCompiler compiler(isolate, Code::STORE_IC);
330 Handle<Code> code;
331 if (ic_state == UNINITIALIZED) {
332 code = compiler.CompileStoreInitialize(flags);
333 } else if (ic_state == PREMONOMORPHIC) {
334 code = compiler.CompileStorePreMonomorphic(flags);
335 } else if (ic_state == GENERIC) {
336 code = compiler.CompileStoreGeneric(flags);
337 } else if (ic_state == MEGAMORPHIC) {
338 code = compiler.CompileStoreMegamorphic(flags);
339 } else {
340 UNREACHABLE();
341 }
342
343 FillCache(isolate, code);
344 return code;
345 }
346
347
348 Handle<Code> PropertyICCompiler::ComputeCompareNil(Handle<Map> receiver_map,
349 CompareNilICStub* stub) {
350 Isolate* isolate = receiver_map->GetIsolate();
351 Handle<String> name(isolate->heap()->empty_string());
352 if (!receiver_map->is_dictionary_map()) {
353 Handle<Code> cached_ic =
354 Find(name, receiver_map, Code::COMPARE_NIL_IC, stub->GetExtraICState());
355 if (!cached_ic.is_null()) return cached_ic;
356 }
357
358 Code::FindAndReplacePattern pattern;
359 pattern.Add(isolate->factory()->meta_map(), receiver_map);
360 Handle<Code> ic = stub->GetCodeCopy(pattern);
361
362 if (!receiver_map->is_dictionary_map()) {
363 Map::UpdateCodeCache(receiver_map, name, ic);
364 }
365
366 return ic;
367 }
368
369
370 // TODO(verwaest): Change this method so it takes in a TypeHandleList.
371 Handle<Code> PropertyICCompiler::ComputeKeyedLoadPolymorphic(
372 MapHandleList* receiver_maps) {
373 Isolate* isolate = receiver_maps->at(0)->GetIsolate();
374 Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
375 Handle<PolymorphicCodeCache> cache =
376 isolate->factory()->polymorphic_code_cache();
377 Handle<Object> probe = cache->Lookup(receiver_maps, flags);
378 if (probe->IsCode()) return Handle<Code>::cast(probe);
379
380 TypeHandleList types(receiver_maps->length());
381 for (int i = 0; i < receiver_maps->length(); i++) {
382 types.Add(HeapType::Class(receiver_maps->at(i), isolate));
383 }
384 CodeHandleList handlers(receiver_maps->length());
385 ElementHandlerCompiler compiler(isolate);
386 compiler.CompileElementHandlers(receiver_maps, &handlers);
387 PropertyICCompiler ic_compiler(isolate, Code::KEYED_LOAD_IC);
388 Handle<Code> code = ic_compiler.CompilePolymorphic(
389 &types, &handlers, isolate->factory()->empty_string(), Code::NORMAL,
390 ELEMENT);
391
392 isolate->counters()->keyed_load_polymorphic_stubs()->Increment();
393
394 PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
395 return code;
396 }
397
398
399 Handle<Code> PropertyICCompiler::ComputePolymorphic(
400 Code::Kind kind, TypeHandleList* types, CodeHandleList* handlers,
401 int valid_types, Handle<Name> name, ExtraICState extra_ic_state) {
402 Handle<Code> handler = handlers->at(0);
403 Code::StubType type = valid_types == 1 ? handler->type() : Code::NORMAL;
404 DCHECK(kind == Code::LOAD_IC || kind == Code::STORE_IC);
405 PropertyICCompiler ic_compiler(name->GetIsolate(), kind, extra_ic_state);
406 return ic_compiler.CompilePolymorphic(types, handlers, name, type, PROPERTY);
407 }
408
409
410 Handle<Code> PropertyICCompiler::ComputeKeyedStorePolymorphic(
411 MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode,
412 StrictMode strict_mode) {
413 Isolate* isolate = receiver_maps->at(0)->GetIsolate();
414 DCHECK(store_mode == STANDARD_STORE ||
415 store_mode == STORE_AND_GROW_NO_TRANSITION ||
416 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
417 store_mode == STORE_NO_TRANSITION_HANDLE_COW);
418 Handle<PolymorphicCodeCache> cache =
419 isolate->factory()->polymorphic_code_cache();
420 ExtraICState extra_state = KeyedStoreIC::ComputeExtraICState(
421 strict_mode, store_mode);
422 Code::Flags flags =
423 Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state);
424 Handle<Object> probe = cache->Lookup(receiver_maps, flags);
425 if (probe->IsCode()) return Handle<Code>::cast(probe);
426
427 PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
428 Handle<Code> code =
429 compiler.CompileKeyedStorePolymorphic(receiver_maps, store_mode);
430 PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
431 return code;
432 }
433
434
435 void StubCache::Clear() {
436 Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal);
437 for (int i = 0; i < kPrimaryTableSize; i++) {
438 primary_[i].key = isolate()->heap()->empty_string();
439 primary_[i].map = NULL;
440 primary_[i].value = empty;
441 }
442 for (int j = 0; j < kSecondaryTableSize; j++) {
443 secondary_[j].key = isolate()->heap()->empty_string();
444 secondary_[j].map = NULL;
445 secondary_[j].value = empty;
446 }
447 }
448
449
450 void StubCache::CollectMatchingMaps(SmallMapList* types,
451 Handle<Name> name,
452 Code::Flags flags,
453 Handle<Context> native_context,
454 Zone* zone) {
455 for (int i = 0; i < kPrimaryTableSize; i++) {
456 if (primary_[i].key == *name) {
457 Map* map = primary_[i].map;
458 // Map can be NULL, if the stub is constant function call
459 // with a primitive receiver.
460 if (map == NULL) continue;
461
462 int offset = PrimaryOffset(*name, flags, map);
463 if (entry(primary_, offset) == &primary_[i] &&
464 !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
465 types->AddMapIfMissing(Handle<Map>(map), zone);
466 }
467 }
468 }
469
470 for (int i = 0; i < kSecondaryTableSize; i++) {
471 if (secondary_[i].key == *name) {
472 Map* map = secondary_[i].map;
473 // Map can be NULL, if the stub is constant function call
474 // with a primitive receiver.
475 if (map == NULL) continue;
476
477 // Lookup in primary table and skip duplicates.
478 int primary_offset = PrimaryOffset(*name, flags, map);
479
480 // Lookup in secondary table and add matches.
481 int offset = SecondaryOffset(*name, flags, primary_offset);
482 if (entry(secondary_, offset) == &secondary_[i] &&
483 !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
484 types->AddMapIfMissing(Handle<Map>(map), zone);
485 }
486 }
487 }
488 }
489
490
491 // ------------------------------------------------------------------------
492 // StubCompiler implementation.
493
494
495 RUNTIME_FUNCTION(StoreCallbackProperty) {
496 Handle<JSObject> receiver = args.at<JSObject>(0);
497 Handle<JSObject> holder = args.at<JSObject>(1);
498 Handle<ExecutableAccessorInfo> callback = args.at<ExecutableAccessorInfo>(2);
499 Handle<Name> name = args.at<Name>(3);
500 Handle<Object> value = args.at<Object>(4);
501 HandleScope scope(isolate);
502
503 DCHECK(callback->IsCompatibleReceiver(*receiver));
504
505 Address setter_address = v8::ToCData<Address>(callback->setter());
506 v8::AccessorNameSetterCallback fun =
507 FUNCTION_CAST<v8::AccessorNameSetterCallback>(setter_address);
508 DCHECK(fun != NULL);
509
510 LOG(isolate, ApiNamedPropertyAccess("store", *receiver, *name));
511 PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
512 *holder);
513 custom_args.Call(fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
514 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
515 return *value;
516 }
517
518
519 /**
520 * Attempts to load a property with an interceptor (which must be present),
521 * but doesn't search the prototype chain.
522 *
523 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
524 * provide any value for the given name.
525 */
526 RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly) {
527 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
528 Handle<Name> name_handle =
529 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
530 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(
531 NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex);
532
533 // TODO(rossberg): Support symbols in the API.
534 if (name_handle->IsSymbol())
535 return isolate->heap()->no_interceptor_result_sentinel();
536 Handle<String> name = Handle<String>::cast(name_handle);
537
538 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
539 v8::NamedPropertyGetterCallback getter =
540 FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address);
541 DCHECK(getter != NULL);
542
543 Handle<JSObject> receiver =
544 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
545 Handle<JSObject> holder =
546 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
547 PropertyCallbackArguments callback_args(
548 isolate, interceptor_info->data(), *receiver, *holder);
549 {
550 // Use the interceptor getter.
551 HandleScope scope(isolate);
552 v8::Handle<v8::Value> r =
553 callback_args.Call(getter, v8::Utils::ToLocal(name));
554 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
555 if (!r.IsEmpty()) {
556 Handle<Object> result = v8::Utils::OpenHandle(*r);
557 result->VerifyApiCallResultType();
558 return *v8::Utils::OpenHandle(*r);
559 }
560 }
561
562 return isolate->heap()->no_interceptor_result_sentinel();
563 }
564
565
566 static Object* ThrowReferenceError(Isolate* isolate, Name* name) {
567 // If the load is non-contextual, just return the undefined result.
568 // Note that both keyed and non-keyed loads may end up here.
569 HandleScope scope(isolate);
570 LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
571 if (ic.contextual_mode() != CONTEXTUAL) {
572 return isolate->heap()->undefined_value();
573 }
574
575 // Throw a reference error.
576 Handle<Name> name_handle(name);
577 Handle<Object> error =
578 isolate->factory()->NewReferenceError("not_defined",
579 HandleVector(&name_handle, 1));
580 return isolate->Throw(*error);
581 }
582
583
584 /**
585 * Loads a property with an interceptor performing post interceptor
586 * lookup if interceptor failed.
587 */
588 RUNTIME_FUNCTION(LoadPropertyWithInterceptor) {
589 HandleScope scope(isolate);
590 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
591 Handle<Name> name =
592 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
593 Handle<JSObject> receiver =
594 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
595 Handle<JSObject> holder =
596 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
597
598 Handle<Object> result;
599 LookupIterator it(receiver, name, holder);
600 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
601 isolate, result, JSObject::GetProperty(&it));
602
603 if (it.IsFound()) return *result;
604
605 return ThrowReferenceError(isolate, Name::cast(args[0]));
606 }
607
608
609 RUNTIME_FUNCTION(StorePropertyWithInterceptor) {
610 HandleScope scope(isolate);
611 DCHECK(args.length() == 3);
612 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
613 Handle<JSObject> receiver = args.at<JSObject>(0);
614 Handle<Name> name = args.at<Name>(1);
615 Handle<Object> value = args.at<Object>(2);
616 #ifdef DEBUG
617 PrototypeIterator iter(isolate, receiver,
618 PrototypeIterator::START_AT_RECEIVER);
619 bool found = false;
620 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
621 Handle<Object> current = PrototypeIterator::GetCurrent(iter);
622 if (current->IsJSObject() &&
623 Handle<JSObject>::cast(current)->HasNamedInterceptor()) {
624 found = true;
625 break;
626 }
627 }
628 DCHECK(found);
629 #endif
630 Handle<Object> result;
631 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
632 isolate, result,
633 JSObject::SetProperty(receiver, name, value, ic.strict_mode()));
634 return *result;
635 }
636
637
638 RUNTIME_FUNCTION(LoadElementWithInterceptor) {
639 HandleScope scope(isolate);
640 Handle<JSObject> receiver = args.at<JSObject>(0);
641 DCHECK(args.smi_at(1) >= 0);
642 uint32_t index = args.smi_at(1);
643 Handle<Object> result;
644 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
645 isolate, result,
646 JSObject::GetElementWithInterceptor(receiver, receiver, index));
647 return *result;
648 }
649
650
651 Handle<Code> PropertyICCompiler::CompileLoadInitialize(Code::Flags flags) {
652 LoadIC::GenerateInitialize(masm());
653 Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadInitialize");
654 PROFILE(isolate(),
655 CodeCreateEvent(Logger::LOAD_INITIALIZE_TAG, *code, 0));
656 return code;
657 }
658
659
660 Handle<Code> PropertyICCompiler::CompileLoadPreMonomorphic(Code::Flags flags) {
661 LoadIC::GeneratePreMonomorphic(masm());
662 Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadPreMonomorphic");
663 PROFILE(isolate(),
664 CodeCreateEvent(Logger::LOAD_PREMONOMORPHIC_TAG, *code, 0));
665 return code;
666 }
667
668
669 Handle<Code> PropertyICCompiler::CompileLoadMegamorphic(Code::Flags flags) {
670 LoadIC::GenerateMegamorphic(masm());
671 Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadMegamorphic");
672 PROFILE(isolate(),
673 CodeCreateEvent(Logger::LOAD_MEGAMORPHIC_TAG, *code, 0));
674 return code;
675 }
676
677
678 Handle<Code> PropertyICCompiler::CompileStoreInitialize(Code::Flags flags) {
679 StoreIC::GenerateInitialize(masm());
680 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
681 PROFILE(isolate(),
682 CodeCreateEvent(Logger::STORE_INITIALIZE_TAG, *code, 0));
683 return code;
684 }
685
686
687 Handle<Code> PropertyICCompiler::CompileStorePreMonomorphic(Code::Flags flags) {
688 StoreIC::GeneratePreMonomorphic(masm());
689 Handle<Code> code = GetCodeWithFlags(flags, "CompileStorePreMonomorphic");
690 PROFILE(isolate(),
691 CodeCreateEvent(Logger::STORE_PREMONOMORPHIC_TAG, *code, 0));
692 return code;
693 }
694
695
696 Handle<Code> PropertyICCompiler::CompileStoreGeneric(Code::Flags flags) {
697 ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
698 StrictMode strict_mode = StoreIC::GetStrictMode(extra_state);
699 StoreIC::GenerateRuntimeSetProperty(masm(), strict_mode);
700 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreGeneric");
701 PROFILE(isolate(),
702 CodeCreateEvent(Logger::STORE_GENERIC_TAG, *code, 0));
703 return code;
704 }
705
706
707 Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) {
708 StoreIC::GenerateMegamorphic(masm());
709 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic");
710 PROFILE(isolate(),
711 CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0));
712 return code;
713 }
714
715
716 #undef CALL_LOGGER_TAG
717
718
719 Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags,
720 const char* name) {
721 // Create code object in the heap.
722 CodeDesc desc;
723 masm()->GetCode(&desc);
724 Handle<Code> code = factory()->NewCode(desc, flags, masm()->CodeObject());
725 if (code->IsCodeStubOrIC()) code->set_stub_key(CodeStub::NoCacheKey());
726 #ifdef ENABLE_DISASSEMBLER
727 if (FLAG_print_code_stubs) {
728 OFStream os(stdout);
729 code->Disassemble(name, os);
730 }
731 #endif
732 return code;
733 }
734
735
736 Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags,
737 Handle<Name> name) {
738 return (FLAG_print_code_stubs && !name.is_null() && name->IsString())
739 ? GetCodeWithFlags(flags, Handle<String>::cast(name)->ToCString().get())
740 : GetCodeWithFlags(flags, NULL);
741 }
742
743
744 #define __ ACCESS_MASM(masm())
745
746
747 Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
748 Handle<Name> name,
749 Label* miss) {
750 PrototypeCheckType check_type = CHECK_ALL_MAPS;
751 int function_index = -1;
752 if (type()->Is(HeapType::String())) {
753 function_index = Context::STRING_FUNCTION_INDEX;
754 } else if (type()->Is(HeapType::Symbol())) {
755 function_index = Context::SYMBOL_FUNCTION_INDEX;
756 } else if (type()->Is(HeapType::Number())) {
757 function_index = Context::NUMBER_FUNCTION_INDEX;
758 } else if (type()->Is(HeapType::Boolean())) {
759 function_index = Context::BOOLEAN_FUNCTION_INDEX;
760 } else {
761 check_type = SKIP_RECEIVER;
762 }
763
764 if (check_type == CHECK_ALL_MAPS) {
765 GenerateDirectLoadGlobalFunctionPrototype(
766 masm(), function_index, scratch1(), miss);
767 Object* function = isolate()->native_context()->get(function_index);
768 Object* prototype = JSFunction::cast(function)->instance_prototype();
769 set_type_for_object(handle(prototype, isolate()));
770 object_reg = scratch1();
771 }
772
773 // Check that the maps starting from the prototype haven't changed.
774 return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name,
775 miss, check_type);
776 }
777
778
779 // Frontend for store uses the name register. It has to be restored before a
780 // miss.
781 Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
782 Handle<Name> name,
783 Label* miss) {
784 return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name,
785 miss, SKIP_RECEIVER);
786 }
787
788
789 bool PropertyICCompiler::IncludesNumberType(TypeHandleList* types) {
790 for (int i = 0; i < types->length(); ++i) {
791 if (types->at(i)->Is(HeapType::Number())) return true;
792 }
793 return false;
794 }
795
796
797 Register PropertyHandlerCompiler::Frontend(Register object_reg,
798 Handle<Name> name) {
799 Label miss;
800 Register reg = FrontendHeader(object_reg, name, &miss);
801 FrontendFooter(name, &miss);
802 return reg;
803 }
804
805
806 void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
807 Label* miss,
808 Register scratch1,
809 Register scratch2) {
810 Register holder_reg;
811 Handle<Map> last_map;
812 if (holder().is_null()) {
813 holder_reg = receiver();
814 last_map = IC::TypeToMap(*type(), isolate());
815 // If |type| has null as its prototype, |holder()| is
816 // Handle<JSObject>::null().
817 DCHECK(last_map->prototype() == isolate()->heap()->null_value());
818 } else {
819 holder_reg = FrontendHeader(receiver(), name, miss);
820 last_map = handle(holder()->map());
821 }
822
823 if (last_map->is_dictionary_map()) {
824 if (last_map->IsJSGlobalObjectMap()) {
825 Handle<JSGlobalObject> global =
826 holder().is_null()
827 ? Handle<JSGlobalObject>::cast(type()->AsConstant()->Value())
828 : Handle<JSGlobalObject>::cast(holder());
829 GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
830 } else {
831 if (!name->IsUniqueName()) {
832 DCHECK(name->IsString());
833 name = factory()->InternalizeString(Handle<String>::cast(name));
834 }
835 DCHECK(holder().is_null() ||
836 holder()->property_dictionary()->FindEntry(name) ==
837 NameDictionary::kNotFound);
838 GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1,
839 scratch2);
840 }
841 }
842 }
843
844
845 Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name,
846 FieldIndex field) {
847 Register reg = Frontend(receiver(), name);
848 __ Move(receiver(), reg);
849 LoadFieldStub stub(isolate(), field);
850 GenerateTailCall(masm(), stub.GetCode());
851 return GetCode(kind(), Code::FAST, name);
852 }
853
854
855 Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name,
856 int constant_index) {
857 Register reg = Frontend(receiver(), name);
858 __ Move(receiver(), reg);
859 LoadConstantStub stub(isolate(), constant_index);
860 GenerateTailCall(masm(), stub.GetCode());
861 return GetCode(kind(), Code::FAST, name);
862 }
863
864
865 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
866 Handle<Name> name) {
867 Label miss;
868 NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
869 GenerateLoadConstant(isolate()->factory()->undefined_value());
870 FrontendFooter(name, &miss);
871 return GetCode(kind(), Code::FAST, name);
872 }
873
874
875 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
876 Handle<Name> name, Handle<ExecutableAccessorInfo> callback) {
877 Register reg = Frontend(receiver(), name);
878 GenerateLoadCallback(reg, callback);
879 return GetCode(kind(), Code::FAST, name);
880 }
881
882
883 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
884 Handle<Name> name, const CallOptimization& call_optimization) {
885 DCHECK(call_optimization.is_simple_api_call());
886 Frontend(receiver(), name);
887 Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate());
888 GenerateFastApiCall(
889 masm(), call_optimization, receiver_map,
890 receiver(), scratch1(), false, 0, NULL);
891 return GetCode(kind(), Code::FAST, name);
892 }
893
894
895 Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
896 LookupIterator* it) {
897 // So far the most popular follow ups for interceptor loads are FIELD and
898 // ExecutableAccessorInfo, so inline only them. Other cases may be added
899 // later.
900 bool inline_followup = it->state() == LookupIterator::PROPERTY;
901 if (inline_followup) {
902 switch (it->property_kind()) {
903 case LookupIterator::DATA:
904 inline_followup = it->property_details().type() == FIELD;
905 break;
906 case LookupIterator::ACCESSOR: {
907 Handle<Object> accessors = it->GetAccessors();
908 inline_followup = accessors->IsExecutableAccessorInfo();
909 if (!inline_followup) break;
910 Handle<ExecutableAccessorInfo> info =
911 Handle<ExecutableAccessorInfo>::cast(accessors);
912 inline_followup = info->getter() != NULL &&
913 ExecutableAccessorInfo::IsCompatibleReceiverType(
914 isolate(), info, type());
915 }
916 }
917 }
918
919 Register reg = Frontend(receiver(), it->name());
920 if (inline_followup) {
921 // TODO(368): Compile in the whole chain: all the interceptors in
922 // prototypes and ultimate answer.
923 GenerateLoadInterceptorWithFollowup(it, reg);
924 } else {
925 GenerateLoadInterceptor(reg);
926 }
927 return GetCode(kind(), Code::FAST, it->name());
928 }
929
930
931 void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
932 LookupIterator* it, Register interceptor_reg) {
933 Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>());
934
935 set_type_for_object(holder());
936 set_holder(real_named_property_holder);
937 Register reg = Frontend(interceptor_reg, it->name());
938
939 switch (it->property_kind()) {
940 case LookupIterator::DATA: {
941 DCHECK_EQ(FIELD, it->property_details().type());
942 __ Move(receiver(), reg);
943 LoadFieldStub stub(isolate(), it->GetFieldIndex());
944 GenerateTailCall(masm(), stub.GetCode());
945 break;
946 }
947 case LookupIterator::ACCESSOR:
948 Handle<ExecutableAccessorInfo> info =
949 Handle<ExecutableAccessorInfo>::cast(it->GetAccessors());
950 DCHECK_NE(NULL, info->getter());
951 GenerateLoadCallback(reg, info);
952 }
953 }
954
955
956 Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<HeapType> type,
957 Handle<Code> handler,
958 Handle<Name> name,
959 IcCheckType check) {
960 TypeHandleList types(1);
961 CodeHandleList handlers(1);
962 types.Add(type);
963 handlers.Add(handler);
964 Code::StubType stub_type = handler->type();
965 return CompilePolymorphic(&types, &handlers, name, stub_type, check);
966 }
967
968
969 Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
970 Handle<Name> name, Handle<JSFunction> getter) {
971 Frontend(receiver(), name);
972 GenerateLoadViaGetter(masm(), type(), receiver(), getter);
973 return GetCode(kind(), Code::FAST, name);
974 }
975
976
977 // TODO(verwaest): Cleanup. holder() is actually the receiver.
978 Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
979 Handle<Map> transition, Handle<Name> name) {
980 Label miss, slow;
981
982 // Ensure no transitions to deprecated maps are followed.
983 __ CheckMapDeprecated(transition, scratch1(), &miss);
984
985 // Check that we are allowed to write this.
986 bool is_nonexistent = holder()->map() == transition->GetBackPointer();
987 if (is_nonexistent) {
988 // Find the top object.
989 Handle<JSObject> last;
990 PrototypeIterator iter(isolate(), holder());
991 while (!iter.IsAtEnd()) {
992 last = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
993 iter.Advance();
994 }
995 if (!last.is_null()) set_holder(last);
996 NonexistentFrontendHeader(name, &miss, scratch1(), scratch2());
997 } else {
998 FrontendHeader(receiver(), name, &miss);
999 DCHECK(holder()->HasFastProperties());
1000 }
1001
1002 GenerateStoreTransition(transition, name, receiver(), this->name(), value(),
1003 scratch1(), scratch2(), scratch3(), &miss, &slow);
1004
1005 GenerateRestoreName(&miss, name);
1006 TailCallBuiltin(masm(), MissBuiltin(kind()));
1007
1008 GenerateRestoreName(&slow, name);
1009 TailCallBuiltin(masm(), SlowBuiltin(kind()));
1010 return GetCode(kind(), Code::FAST, name);
1011 }
1012
1013
1014 Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) {
1015 Label miss;
1016 GenerateStoreField(it, value(), &miss);
1017 __ bind(&miss);
1018 TailCallBuiltin(masm(), MissBuiltin(kind()));
1019 return GetCode(kind(), Code::FAST, it->name());
1020 }
1021
1022
1023 Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
1024 Handle<JSObject> object, Handle<Name> name, Handle<JSFunction> setter) {
1025 Frontend(receiver(), name);
1026 GenerateStoreViaSetter(masm(), type(), receiver(), setter);
1027
1028 return GetCode(kind(), Code::FAST, name);
1029 }
1030
1031
1032 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
1033 Handle<JSObject> object, Handle<Name> name,
1034 const CallOptimization& call_optimization) {
1035 Frontend(receiver(), name);
1036 Register values[] = { value() };
1037 GenerateFastApiCall(
1038 masm(), call_optimization, handle(object->map()),
1039 receiver(), scratch1(), true, 1, values);
1040 return GetCode(kind(), Code::FAST, name);
1041 }
1042
1043
1044 Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic(
1045 Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
1046 ElementsKind elements_kind = receiver_map->elements_kind();
1047 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
1048 Handle<Code> stub;
1049 if (receiver_map->has_fast_elements() ||
1050 receiver_map->has_external_array_elements() ||
1051 receiver_map->has_fixed_typed_array_elements()) {
1052 stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind,
1053 store_mode).GetCode();
1054 } else {
1055 stub = StoreElementStub(isolate(), is_jsarray, elements_kind, store_mode)
1056 .GetCode();
1057 }
1058
1059 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1060
1061 TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
1062
1063 return GetCode(kind(), Code::NORMAL, factory()->empty_string());
1064 }
1065
1066
1067 #undef __
1068
1069
1070 void PropertyAccessCompiler::TailCallBuiltin(MacroAssembler* masm,
1071 Builtins::Name name) {
1072 Handle<Code> code(masm->isolate()->builtins()->builtin(name));
1073 GenerateTailCall(masm, code);
1074 }
1075
1076
1077 Register* PropertyAccessCompiler::GetCallingConvention(Code::Kind kind) {
1078 if (kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC) {
1079 return load_calling_convention();
1080 }
1081 DCHECK(kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC);
1082 return store_calling_convention();
1083 }
1084
1085
1086 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type,
1087 Handle<Name> name,
1088 InlineCacheState state) {
1089 Code::Flags flags =
1090 Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder());
1091 Handle<Code> code = GetCodeWithFlags(flags, name);
1092 IC::RegisterWeakMapDependency(code);
1093 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
1094 return code;
1095 }
1096
1097
1098 Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
1099 Code::StubType type,
1100 Handle<Name> name) {
1101 Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder());
1102 Handle<Code> code = GetCodeWithFlags(flags, name);
1103 PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, *name));
1104 return code;
1105 }
1106
1107
1108 void ElementHandlerCompiler::CompileElementHandlers(
1109 MapHandleList* receiver_maps, CodeHandleList* handlers) {
1110 for (int i = 0; i < receiver_maps->length(); ++i) {
1111 Handle<Map> receiver_map = receiver_maps->at(i);
1112 Handle<Code> cached_stub;
1113
1114 if ((receiver_map->instance_type() & kNotStringTag) == 0) {
1115 cached_stub = isolate()->builtins()->KeyedLoadIC_String();
1116 } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
1117 cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
1118 } else {
1119 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1120 ElementsKind elements_kind = receiver_map->elements_kind();
1121
1122 if (IsFastElementsKind(elements_kind) ||
1123 IsExternalArrayElementsKind(elements_kind) ||
1124 IsFixedTypedArrayElementsKind(elements_kind)) {
1125 cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind)
1126 .GetCode();
1127 } else if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) {
1128 cached_stub = isolate()->builtins()->KeyedLoadIC_SloppyArguments();
1129 } else {
1130 DCHECK(elements_kind == DICTIONARY_ELEMENTS);
1131 cached_stub = LoadDictionaryElementStub(isolate()).GetCode();
1132 }
1133 }
1134
1135 handlers->Add(cached_stub);
1136 }
1137 }
1138
1139
1140 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
1141 MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode) {
1142 // Collect MONOMORPHIC stubs for all |receiver_maps|.
1143 CodeHandleList handlers(receiver_maps->length());
1144 MapHandleList transitioned_maps(receiver_maps->length());
1145 for (int i = 0; i < receiver_maps->length(); ++i) {
1146 Handle<Map> receiver_map(receiver_maps->at(i));
1147 Handle<Code> cached_stub;
1148 Handle<Map> transitioned_map =
1149 receiver_map->FindTransitionedMap(receiver_maps);
1150
1151 // TODO(mvstanton): The code below is doing pessimistic elements
1152 // transitions. I would like to stop doing that and rely on Allocation Site
1153 // Tracking to do a better job of ensuring the data types are what they need
1154 // to be. Not all the elements are in place yet, pessimistic elements
1155 // transitions are still important for performance.
1156 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1157 ElementsKind elements_kind = receiver_map->elements_kind();
1158 if (!transitioned_map.is_null()) {
1159 cached_stub =
1160 ElementsTransitionAndStoreStub(isolate(), elements_kind,
1161 transitioned_map->elements_kind(),
1162 is_js_array, store_mode).GetCode();
1163 } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
1164 cached_stub = isolate()->builtins()->KeyedStoreIC_Slow();
1165 } else {
1166 if (receiver_map->has_fast_elements() ||
1167 receiver_map->has_external_array_elements() ||
1168 receiver_map->has_fixed_typed_array_elements()) {
1169 cached_stub = StoreFastElementStub(isolate(), is_js_array,
1170 elements_kind, store_mode).GetCode();
1171 } else {
1172 cached_stub = StoreElementStub(isolate(), is_js_array, elements_kind,
1173 store_mode).GetCode();
1174 }
1175 }
1176 DCHECK(!cached_stub.is_null());
1177 handlers.Add(cached_stub);
1178 transitioned_maps.Add(transitioned_map);
1179 }
1180
1181 Handle<Code> code = CompileKeyedStorePolymorphic(receiver_maps, &handlers,
1182 &transitioned_maps);
1183 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
1184 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, 0));
1185 return code;
1186 }
1187
1188
1189 void ElementHandlerCompiler::GenerateStoreDictionaryElement(
1190 MacroAssembler* masm) {
1191 KeyedStoreIC::GenerateSlow(masm);
1192 }
1193
1194
1195 CallOptimization::CallOptimization(Handle<JSFunction> function) {
1196 Initialize(function);
1197 }
1198
1199
1200 Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
1201 Handle<Map> object_map,
1202 HolderLookup* holder_lookup) const {
1203 DCHECK(is_simple_api_call());
1204 if (!object_map->IsJSObjectMap()) {
1205 *holder_lookup = kHolderNotFound;
1206 return Handle<JSObject>::null();
1207 }
1208 if (expected_receiver_type_.is_null() ||
1209 expected_receiver_type_->IsTemplateFor(*object_map)) {
1210 *holder_lookup = kHolderIsReceiver;
1211 return Handle<JSObject>::null();
1212 }
1213 while (true) {
1214 if (!object_map->prototype()->IsJSObject()) break;
1215 Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
1216 if (!prototype->map()->is_hidden_prototype()) break;
1217 object_map = handle(prototype->map());
1218 if (expected_receiver_type_->IsTemplateFor(*object_map)) {
1219 *holder_lookup = kHolderFound;
1220 return prototype;
1221 }
1222 }
1223 *holder_lookup = kHolderNotFound;
1224 return Handle<JSObject>::null();
1225 }
1226
1227
1228 bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
1229 Handle<JSObject> holder) const {
1230 DCHECK(is_simple_api_call());
1231 if (!receiver->IsJSObject()) return false;
1232 Handle<Map> map(JSObject::cast(*receiver)->map());
1233 HolderLookup holder_lookup;
1234 Handle<JSObject> api_holder =
1235 LookupHolderOfExpectedType(map, &holder_lookup);
1236 switch (holder_lookup) {
1237 case kHolderNotFound:
1238 return false;
1239 case kHolderIsReceiver:
1240 return true;
1241 case kHolderFound:
1242 if (api_holder.is_identical_to(holder)) return true;
1243 // Check if holder is in prototype chain of api_holder.
1244 {
1245 JSObject* object = *api_holder;
1246 while (true) {
1247 Object* prototype = object->map()->prototype();
1248 if (!prototype->IsJSObject()) return false;
1249 if (prototype == *holder) return true;
1250 object = JSObject::cast(prototype);
1251 }
1252 }
1253 break;
1254 }
1255 UNREACHABLE();
1256 return false;
1257 }
1258
1259
1260 void CallOptimization::Initialize(Handle<JSFunction> function) {
1261 constant_function_ = Handle<JSFunction>::null();
1262 is_simple_api_call_ = false;
1263 expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
1264 api_call_info_ = Handle<CallHandlerInfo>::null();
1265
1266 if (function.is_null() || !function->is_compiled()) return;
1267
1268 constant_function_ = function;
1269 AnalyzePossibleApiFunction(function);
1270 }
1271
1272
1273 void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
1274 if (!function->shared()->IsApiFunction()) return;
1275 Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
1276
1277 // Require a C++ callback.
1278 if (info->call_code()->IsUndefined()) return;
1279 api_call_info_ =
1280 Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
1281
1282 // Accept signatures that either have no restrictions at all or
1283 // only have restrictions on the receiver.
1284 if (!info->signature()->IsUndefined()) {
1285 Handle<SignatureInfo> signature =
1286 Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
1287 if (!signature->args()->IsUndefined()) return;
1288 if (!signature->receiver()->IsUndefined()) {
1289 expected_receiver_type_ =
1290 Handle<FunctionTemplateInfo>(
1291 FunctionTemplateInfo::cast(signature->receiver()));
1292 }
1293 }
1294
1295 is_simple_api_call_ = true;
1296 }
1297
1298
1299 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/stub-cache.h ('k') | src/type-info.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698