OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
8 #include "src/api.h" | 8 #include "src/api.h" |
9 #include "src/arguments.h" | 9 #include "src/arguments.h" |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
11 #include "src/conversions.h" | 11 #include "src/conversions.h" |
12 #include "src/execution.h" | 12 #include "src/execution.h" |
13 #include "src/ic-inl.h" | 13 #include "src/ic/ic-inl.h" |
| 14 #include "src/ic/ic-compiler.h" |
| 15 #include "src/ic/stub-cache.h" |
14 #include "src/prototype.h" | 16 #include "src/prototype.h" |
15 #include "src/runtime.h" | 17 #include "src/runtime.h" |
16 #include "src/stub-cache.h" | |
17 | 18 |
18 namespace v8 { | 19 namespace v8 { |
19 namespace internal { | 20 namespace internal { |
20 | 21 |
21 char IC::TransitionMarkFromState(IC::State state) { | 22 char IC::TransitionMarkFromState(IC::State state) { |
22 switch (state) { | 23 switch (state) { |
23 case UNINITIALIZED: return '0'; | 24 case UNINITIALIZED: |
24 case PREMONOMORPHIC: return '.'; | 25 return '0'; |
25 case MONOMORPHIC: return '1'; | 26 case PREMONOMORPHIC: |
| 27 return '.'; |
| 28 case MONOMORPHIC: |
| 29 return '1'; |
26 case PROTOTYPE_FAILURE: | 30 case PROTOTYPE_FAILURE: |
27 return '^'; | 31 return '^'; |
28 case POLYMORPHIC: return 'P'; | 32 case POLYMORPHIC: |
29 case MEGAMORPHIC: return 'N'; | 33 return 'P'; |
30 case GENERIC: return 'G'; | 34 case MEGAMORPHIC: |
| 35 return 'N'; |
| 36 case GENERIC: |
| 37 return 'G'; |
31 | 38 |
32 // We never see the debugger states here, because the state is | 39 // We never see the debugger states here, because the state is |
33 // computed from the original code - not the patched code. Let | 40 // computed from the original code - not the patched code. Let |
34 // these cases fall through to the unreachable code below. | 41 // these cases fall through to the unreachable code below. |
35 case DEBUG_STUB: break; | 42 case DEBUG_STUB: |
| 43 break; |
36 // Type-vector-based ICs resolve state to one of the above. | 44 // Type-vector-based ICs resolve state to one of the above. |
37 case DEFAULT: | 45 case DEFAULT: |
38 break; | 46 break; |
39 } | 47 } |
40 UNREACHABLE(); | 48 UNREACHABLE(); |
41 return 0; | 49 return 0; |
42 } | 50 } |
43 | 51 |
44 | 52 |
45 const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) { | 53 const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 #endif | 123 #endif |
116 PrintF("]\n"); | 124 PrintF("]\n"); |
117 } | 125 } |
118 } | 126 } |
119 | 127 |
120 #define TRACE_IC(type, name) TraceIC(type, name) | 128 #define TRACE_IC(type, name) TraceIC(type, name) |
121 #define TRACE_VECTOR_IC(type, name, old_state, new_state) \ | 129 #define TRACE_VECTOR_IC(type, name, old_state, new_state) \ |
122 TraceIC(type, name, old_state, new_state) | 130 TraceIC(type, name, old_state, new_state) |
123 | 131 |
124 IC::IC(FrameDepth depth, Isolate* isolate) | 132 IC::IC(FrameDepth depth, Isolate* isolate) |
125 : isolate_(isolate), | 133 : isolate_(isolate), target_set_(false), target_maps_set_(false) { |
126 target_set_(false), | |
127 target_maps_set_(false) { | |
128 // To improve the performance of the (much used) IC code, we unfold a few | 134 // To improve the performance of the (much used) IC code, we unfold a few |
129 // levels of the stack frame iteration code. This yields a ~35% speedup when | 135 // levels of the stack frame iteration code. This yields a ~35% speedup when |
130 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag. | 136 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag. |
131 const Address entry = | 137 const Address entry = Isolate::c_entry_fp(isolate->thread_local_top()); |
132 Isolate::c_entry_fp(isolate->thread_local_top()); | |
133 Address constant_pool = NULL; | 138 Address constant_pool = NULL; |
134 if (FLAG_enable_ool_constant_pool) { | 139 if (FLAG_enable_ool_constant_pool) { |
135 constant_pool = Memory::Address_at( | 140 constant_pool = |
136 entry + ExitFrameConstants::kConstantPoolOffset); | 141 Memory::Address_at(entry + ExitFrameConstants::kConstantPoolOffset); |
137 } | 142 } |
138 Address* pc_address = | 143 Address* pc_address = |
139 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); | 144 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); |
140 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); | 145 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); |
141 // If there's another JavaScript frame on the stack or a | 146 // If there's another JavaScript frame on the stack or a |
142 // StubFailureTrampoline, we need to look one frame further down the stack to | 147 // StubFailureTrampoline, we need to look one frame further down the stack to |
143 // find the frame pointer and the return address stack slot. | 148 // find the frame pointer and the return address stack slot. |
144 if (depth == EXTRA_CALL_FRAME) { | 149 if (depth == EXTRA_CALL_FRAME) { |
145 if (FLAG_enable_ool_constant_pool) { | 150 if (FLAG_enable_ool_constant_pool) { |
146 constant_pool = Memory::Address_at( | 151 constant_pool = |
147 fp + StandardFrameConstants::kConstantPoolOffset); | 152 Memory::Address_at(fp + StandardFrameConstants::kConstantPoolOffset); |
148 } | 153 } |
149 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset; | 154 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset; |
150 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset); | 155 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset); |
151 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset); | 156 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset); |
152 } | 157 } |
153 #ifdef DEBUG | 158 #ifdef DEBUG |
154 StackFrameIterator it(isolate); | 159 StackFrameIterator it(isolate); |
155 for (int i = 0; i < depth + 1; i++) it.Advance(); | 160 for (int i = 0; i < depth + 1; i++) it.Advance(); |
156 StackFrame* frame = it.frame(); | 161 StackFrame* frame = it.frame(); |
157 DCHECK(fp == frame->fp() && pc_address == frame->pc_address()); | 162 DCHECK(fp == frame->fp() && pc_address == frame->pc_address()); |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 // The builtins object is special. It only changes when JavaScript | 320 // The builtins object is special. It only changes when JavaScript |
316 // builtins are loaded lazily. It is important to keep inline | 321 // builtins are loaded lazily. It is important to keep inline |
317 // caches for the builtins object monomorphic. Therefore, if we get | 322 // caches for the builtins object monomorphic. Therefore, if we get |
318 // an inline cache miss for the builtins object after lazily loading | 323 // an inline cache miss for the builtins object after lazily loading |
319 // JavaScript builtins, we return uninitialized as the state to | 324 // JavaScript builtins, we return uninitialized as the state to |
320 // force the inline cache back to monomorphic state. | 325 // force the inline cache back to monomorphic state. |
321 if (receiver->IsJSBuiltinsObject()) state_ = UNINITIALIZED; | 326 if (receiver->IsJSBuiltinsObject()) state_ = UNINITIALIZED; |
322 } | 327 } |
323 | 328 |
324 | 329 |
325 MaybeHandle<Object> IC::TypeError(const char* type, | 330 MaybeHandle<Object> IC::TypeError(const char* type, Handle<Object> object, |
326 Handle<Object> object, | |
327 Handle<Object> key) { | 331 Handle<Object> key) { |
328 HandleScope scope(isolate()); | 332 HandleScope scope(isolate()); |
329 Handle<Object> args[2] = { key, object }; | 333 Handle<Object> args[2] = {key, object}; |
330 Handle<Object> error = isolate()->factory()->NewTypeError( | 334 Handle<Object> error = |
331 type, HandleVector(args, 2)); | 335 isolate()->factory()->NewTypeError(type, HandleVector(args, 2)); |
332 return isolate()->Throw<Object>(error); | 336 return isolate()->Throw<Object>(error); |
333 } | 337 } |
334 | 338 |
335 | 339 |
336 MaybeHandle<Object> IC::ReferenceError(const char* type, Handle<Name> name) { | 340 MaybeHandle<Object> IC::ReferenceError(const char* type, Handle<Name> name) { |
337 HandleScope scope(isolate()); | 341 HandleScope scope(isolate()); |
338 Handle<Object> error = isolate()->factory()->NewReferenceError( | 342 Handle<Object> error = |
339 type, HandleVector(&name, 1)); | 343 isolate()->factory()->NewReferenceError(type, HandleVector(&name, 1)); |
340 return isolate()->Throw<Object>(error); | 344 return isolate()->Throw<Object>(error); |
341 } | 345 } |
342 | 346 |
343 | 347 |
344 static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state, | 348 static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state, |
345 int* polymorphic_delta, | 349 int* polymorphic_delta, |
346 int* generic_delta) { | 350 int* generic_delta) { |
347 switch (old_state) { | 351 switch (old_state) { |
348 case UNINITIALIZED: | 352 case UNINITIALIZED: |
349 case PREMONOMORPHIC: | 353 case PREMONOMORPHIC: |
(...skipping 24 matching lines...) Expand all Loading... |
374 case DEBUG_STUB: | 378 case DEBUG_STUB: |
375 case DEFAULT: | 379 case DEFAULT: |
376 UNREACHABLE(); | 380 UNREACHABLE(); |
377 } | 381 } |
378 } | 382 } |
379 | 383 |
380 | 384 |
381 void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address, | 385 void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address, |
382 State old_state, State new_state, | 386 State old_state, State new_state, |
383 bool target_remains_ic_stub) { | 387 bool target_remains_ic_stub) { |
384 Code* host = isolate-> | 388 Code* host = |
385 inner_pointer_to_code_cache()->GetCacheEntry(address)->code; | 389 isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code; |
386 if (host->kind() != Code::FUNCTION) return; | 390 if (host->kind() != Code::FUNCTION) return; |
387 | 391 |
388 if (FLAG_type_info_threshold > 0 && target_remains_ic_stub && | 392 if (FLAG_type_info_threshold > 0 && target_remains_ic_stub && |
389 // Not all Code objects have TypeFeedbackInfo. | 393 // Not all Code objects have TypeFeedbackInfo. |
390 host->type_feedback_info()->IsTypeFeedbackInfo()) { | 394 host->type_feedback_info()->IsTypeFeedbackInfo()) { |
391 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic. | 395 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic. |
392 int generic_delta = 0; // "Generic" here includes megamorphic. | 396 int generic_delta = 0; // "Generic" here includes megamorphic. |
393 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta, | 397 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta, |
394 &generic_delta); | 398 &generic_delta); |
395 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info()); | 399 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info()); |
396 info->change_ic_with_type_info_count(polymorphic_delta); | 400 info->change_ic_with_type_info_count(polymorphic_delta); |
397 info->change_ic_generic_count(generic_delta); | 401 info->change_ic_generic_count(generic_delta); |
398 } | 402 } |
399 if (host->type_feedback_info()->IsTypeFeedbackInfo()) { | 403 if (host->type_feedback_info()->IsTypeFeedbackInfo()) { |
400 TypeFeedbackInfo* info = | 404 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info()); |
401 TypeFeedbackInfo::cast(host->type_feedback_info()); | |
402 info->change_own_type_change_checksum(); | 405 info->change_own_type_change_checksum(); |
403 } | 406 } |
404 host->set_profiler_ticks(0); | 407 host->set_profiler_ticks(0); |
405 isolate->runtime_profiler()->NotifyICChanged(); | 408 isolate->runtime_profiler()->NotifyICChanged(); |
406 // TODO(2029): When an optimized function is patched, it would | 409 // TODO(2029): When an optimized function is patched, it would |
407 // be nice to propagate the corresponding type information to its | 410 // be nice to propagate the corresponding type information to its |
408 // unoptimized version for the benefit of later inlining. | 411 // unoptimized version for the benefit of later inlining. |
409 } | 412 } |
410 | 413 |
411 | 414 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 if (mode == RelocInfo::EMBEDDED_OBJECT && | 462 if (mode == RelocInfo::EMBEDDED_OBJECT && |
460 it.rinfo()->target_object()->IsMap()) { | 463 it.rinfo()->target_object()->IsMap()) { |
461 it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER); | 464 it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER); |
462 } | 465 } |
463 } | 466 } |
464 CpuFeatures::FlushICache(stub->instruction_start(), stub->instruction_size()); | 467 CpuFeatures::FlushICache(stub->instruction_start(), stub->instruction_size()); |
465 } | 468 } |
466 | 469 |
467 | 470 |
468 void IC::Clear(Isolate* isolate, Address address, | 471 void IC::Clear(Isolate* isolate, Address address, |
469 ConstantPoolArray* constant_pool) { | 472 ConstantPoolArray* constant_pool) { |
470 Code* target = GetTargetAtAddress(address, constant_pool); | 473 Code* target = GetTargetAtAddress(address, constant_pool); |
471 | 474 |
472 // Don't clear debug break inline cache as it will remove the break point. | 475 // Don't clear debug break inline cache as it will remove the break point. |
473 if (target->is_debug_stub()) return; | 476 if (target->is_debug_stub()) return; |
474 | 477 |
475 switch (target->kind()) { | 478 switch (target->kind()) { |
476 case Code::LOAD_IC: | 479 case Code::LOAD_IC: |
477 return LoadIC::Clear(isolate, address, target, constant_pool); | 480 return LoadIC::Clear(isolate, address, target, constant_pool); |
478 case Code::KEYED_LOAD_IC: | 481 case Code::KEYED_LOAD_IC: |
479 return KeyedLoadIC::Clear(isolate, address, target, constant_pool); | 482 return KeyedLoadIC::Clear(isolate, address, target, constant_pool); |
480 case Code::STORE_IC: | 483 case Code::STORE_IC: |
481 return StoreIC::Clear(isolate, address, target, constant_pool); | 484 return StoreIC::Clear(isolate, address, target, constant_pool); |
482 case Code::KEYED_STORE_IC: | 485 case Code::KEYED_STORE_IC: |
483 return KeyedStoreIC::Clear(isolate, address, target, constant_pool); | 486 return KeyedStoreIC::Clear(isolate, address, target, constant_pool); |
484 case Code::CALL_IC: | 487 case Code::CALL_IC: |
485 return CallIC::Clear(isolate, address, target, constant_pool); | 488 return CallIC::Clear(isolate, address, target, constant_pool); |
486 case Code::COMPARE_IC: | 489 case Code::COMPARE_IC: |
487 return CompareIC::Clear(isolate, address, target, constant_pool); | 490 return CompareIC::Clear(isolate, address, target, constant_pool); |
488 case Code::COMPARE_NIL_IC: | 491 case Code::COMPARE_NIL_IC: |
489 return CompareNilIC::Clear(address, target, constant_pool); | 492 return CompareNilIC::Clear(address, target, constant_pool); |
490 case Code::BINARY_OP_IC: | 493 case Code::BINARY_OP_IC: |
491 case Code::TO_BOOLEAN_IC: | 494 case Code::TO_BOOLEAN_IC: |
492 // Clearing these is tricky and does not | 495 // Clearing these is tricky and does not |
493 // make any performance difference. | 496 // make any performance difference. |
494 return; | 497 return; |
495 default: UNREACHABLE(); | 498 default: |
| 499 UNREACHABLE(); |
496 } | 500 } |
497 } | 501 } |
498 | 502 |
499 | 503 |
500 void KeyedLoadIC::Clear(Isolate* isolate, | 504 void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target, |
501 Address address, | |
502 Code* target, | |
503 ConstantPoolArray* constant_pool) { | 505 ConstantPoolArray* constant_pool) { |
504 if (IsCleared(target)) return; | 506 if (IsCleared(target)) return; |
505 // Make sure to also clear the map used in inline fast cases. If we | 507 // Make sure to also clear the map used in inline fast cases. If we |
506 // do not clear these maps, cached code can keep objects alive | 508 // do not clear these maps, cached code can keep objects alive |
507 // through the embedded maps. | 509 // through the embedded maps. |
508 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate), constant_pool); | 510 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate), constant_pool); |
509 } | 511 } |
510 | 512 |
511 | 513 |
512 void CallIC::Clear(Isolate* isolate, | 514 void CallIC::Clear(Isolate* isolate, Address address, Code* target, |
513 Address address, | |
514 Code* target, | |
515 ConstantPoolArray* constant_pool) { | 515 ConstantPoolArray* constant_pool) { |
516 // Currently, CallIC doesn't have state changes. | 516 // Currently, CallIC doesn't have state changes. |
517 } | 517 } |
518 | 518 |
519 | 519 |
520 void LoadIC::Clear(Isolate* isolate, | 520 void LoadIC::Clear(Isolate* isolate, Address address, Code* target, |
521 Address address, | |
522 Code* target, | |
523 ConstantPoolArray* constant_pool) { | 521 ConstantPoolArray* constant_pool) { |
524 if (IsCleared(target)) return; | 522 if (IsCleared(target)) return; |
525 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::LOAD_IC, | 523 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::LOAD_IC, |
526 target->extra_ic_state()); | 524 target->extra_ic_state()); |
527 SetTargetAtAddress(address, code, constant_pool); | 525 SetTargetAtAddress(address, code, constant_pool); |
528 } | 526 } |
529 | 527 |
530 | 528 |
531 void StoreIC::Clear(Isolate* isolate, | 529 void StoreIC::Clear(Isolate* isolate, Address address, Code* target, |
532 Address address, | |
533 Code* target, | |
534 ConstantPoolArray* constant_pool) { | 530 ConstantPoolArray* constant_pool) { |
535 if (IsCleared(target)) return; | 531 if (IsCleared(target)) return; |
536 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::STORE_IC, | 532 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::STORE_IC, |
537 target->extra_ic_state()); | 533 target->extra_ic_state()); |
538 SetTargetAtAddress(address, code, constant_pool); | 534 SetTargetAtAddress(address, code, constant_pool); |
539 } | 535 } |
540 | 536 |
541 | 537 |
542 void KeyedStoreIC::Clear(Isolate* isolate, | 538 void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target, |
543 Address address, | |
544 Code* target, | |
545 ConstantPoolArray* constant_pool) { | 539 ConstantPoolArray* constant_pool) { |
546 if (IsCleared(target)) return; | 540 if (IsCleared(target)) return; |
547 SetTargetAtAddress(address, | 541 SetTargetAtAddress( |
548 *pre_monomorphic_stub( | 542 address, *pre_monomorphic_stub( |
549 isolate, StoreIC::GetStrictMode(target->extra_ic_state())), | 543 isolate, StoreIC::GetStrictMode(target->extra_ic_state())), |
550 constant_pool); | 544 constant_pool); |
551 } | 545 } |
552 | 546 |
553 | 547 |
554 void CompareIC::Clear(Isolate* isolate, | 548 void CompareIC::Clear(Isolate* isolate, Address address, Code* target, |
555 Address address, | |
556 Code* target, | |
557 ConstantPoolArray* constant_pool) { | 549 ConstantPoolArray* constant_pool) { |
558 DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC); | 550 DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC); |
559 CompareIC::State handler_state; | 551 CompareIC::State handler_state; |
560 Token::Value op; | 552 Token::Value op; |
561 ICCompareStub::DecodeKey(target->stub_key(), NULL, NULL, &handler_state, &op); | 553 ICCompareStub::DecodeKey(target->stub_key(), NULL, NULL, &handler_state, &op); |
562 // Only clear CompareICs that can retain objects. | 554 // Only clear CompareICs that can retain objects. |
563 if (handler_state != KNOWN_OBJECT) return; | 555 if (handler_state != KNOWN_OBJECT) return; |
564 SetTargetAtAddress(address, GetRawUninitialized(isolate, op), constant_pool); | 556 SetTargetAtAddress(address, GetRawUninitialized(isolate, op), constant_pool); |
565 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); | 557 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); |
566 } | 558 } |
(...skipping 30 matching lines...) Expand all Loading... |
597 uint32_t index; | 589 uint32_t index; |
598 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) { | 590 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) { |
599 // Rewrite to the generic keyed load stub. | 591 // Rewrite to the generic keyed load stub. |
600 if (FLAG_use_ic) { | 592 if (FLAG_use_ic) { |
601 set_target(*KeyedLoadIC::generic_stub(isolate())); | 593 set_target(*KeyedLoadIC::generic_stub(isolate())); |
602 TRACE_IC("LoadIC", name); | 594 TRACE_IC("LoadIC", name); |
603 TRACE_GENERIC_IC(isolate(), "LoadIC", "name as array index"); | 595 TRACE_GENERIC_IC(isolate(), "LoadIC", "name as array index"); |
604 } | 596 } |
605 Handle<Object> result; | 597 Handle<Object> result; |
606 ASSIGN_RETURN_ON_EXCEPTION( | 598 ASSIGN_RETURN_ON_EXCEPTION( |
607 isolate(), | 599 isolate(), result, |
608 result, | 600 Runtime::GetElementOrCharAt(isolate(), object, index), Object); |
609 Runtime::GetElementOrCharAt(isolate(), object, index), | |
610 Object); | |
611 return result; | 601 return result; |
612 } | 602 } |
613 | 603 |
614 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic; | 604 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic; |
615 | 605 |
616 // Named lookup in the object. | 606 // Named lookup in the object. |
617 LookupIterator it(object, name); | 607 LookupIterator it(object, name); |
618 LookupForRead(&it); | 608 LookupForRead(&it); |
619 | 609 |
620 if (it.IsFound() || !IsUndeclaredGlobal(object)) { | 610 if (it.IsFound() || !IsUndeclaredGlobal(object)) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
666 Handle<HeapType> current_type = types.at(i); | 656 Handle<HeapType> current_type = types.at(i); |
667 if (current_type->IsClass() && | 657 if (current_type->IsClass() && |
668 current_type->AsClass()->Map()->is_deprecated()) { | 658 current_type->AsClass()->Map()->is_deprecated()) { |
669 // Filter out deprecated maps to ensure their instances get migrated. | 659 // Filter out deprecated maps to ensure their instances get migrated. |
670 ++deprecated_types; | 660 ++deprecated_types; |
671 } else if (type->NowIs(current_type)) { | 661 } else if (type->NowIs(current_type)) { |
672 // If the receiver type is already in the polymorphic IC, this indicates | 662 // If the receiver type is already in the polymorphic IC, this indicates |
673 // there was a prototoype chain failure. In that case, just overwrite the | 663 // there was a prototoype chain failure. In that case, just overwrite the |
674 // handler. | 664 // handler. |
675 handler_to_overwrite = i; | 665 handler_to_overwrite = i; |
676 } else if (handler_to_overwrite == -1 && | 666 } else if (handler_to_overwrite == -1 && current_type->IsClass() && |
677 current_type->IsClass() && | |
678 type->IsClass() && | 667 type->IsClass() && |
679 IsTransitionOfMonomorphicTarget(*current_type->AsClass()->Map(), | 668 IsTransitionOfMonomorphicTarget(*current_type->AsClass()->Map(), |
680 *type->AsClass()->Map())) { | 669 *type->AsClass()->Map())) { |
681 handler_to_overwrite = i; | 670 handler_to_overwrite = i; |
682 } | 671 } |
683 } | 672 } |
684 | 673 |
685 int number_of_valid_types = | 674 int number_of_valid_types = |
686 number_of_types - deprecated_types - (handler_to_overwrite != -1); | 675 number_of_types - deprecated_types - (handler_to_overwrite != -1); |
687 | 676 |
688 if (number_of_valid_types >= 4) return false; | 677 if (number_of_valid_types >= 4) return false; |
689 if (number_of_types == 0) return false; | 678 if (number_of_types == 0) return false; |
690 if (!target()->FindHandlers(&handlers, types.length())) return false; | 679 if (!target()->FindHandlers(&handlers, types.length())) return false; |
691 | 680 |
692 number_of_valid_types++; | 681 number_of_valid_types++; |
693 if (number_of_valid_types > 1 && target()->is_keyed_stub()) return false; | 682 if (number_of_valid_types > 1 && target()->is_keyed_stub()) return false; |
694 Handle<Code> ic; | 683 Handle<Code> ic; |
695 if (number_of_valid_types == 1) { | 684 if (number_of_valid_types == 1) { |
696 ic = PropertyICCompiler::ComputeMonomorphic(kind(), name, type, code, | 685 ic = PropertyICCompiler::ComputeMonomorphic(kind(), name, type, code, |
(...skipping 12 matching lines...) Expand all Loading... |
709 number_of_valid_types, name, | 698 number_of_valid_types, name, |
710 extra_ic_state()); | 699 extra_ic_state()); |
711 } | 700 } |
712 set_target(*ic); | 701 set_target(*ic); |
713 return true; | 702 return true; |
714 } | 703 } |
715 | 704 |
716 | 705 |
717 Handle<HeapType> IC::CurrentTypeOf(Handle<Object> object, Isolate* isolate) { | 706 Handle<HeapType> IC::CurrentTypeOf(Handle<Object> object, Isolate* isolate) { |
718 return object->IsJSGlobalObject() | 707 return object->IsJSGlobalObject() |
719 ? HeapType::Constant(Handle<JSGlobalObject>::cast(object), isolate) | 708 ? HeapType::Constant(Handle<JSGlobalObject>::cast(object), isolate) |
720 : HeapType::NowOf(object, isolate); | 709 : HeapType::NowOf(object, isolate); |
721 } | 710 } |
722 | 711 |
723 | 712 |
724 Handle<Map> IC::TypeToMap(HeapType* type, Isolate* isolate) { | 713 Handle<Map> IC::TypeToMap(HeapType* type, Isolate* isolate) { |
725 if (type->Is(HeapType::Number())) | 714 if (type->Is(HeapType::Number())) |
726 return isolate->factory()->heap_number_map(); | 715 return isolate->factory()->heap_number_map(); |
727 if (type->Is(HeapType::Boolean())) return isolate->factory()->boolean_map(); | 716 if (type->Is(HeapType::Boolean())) return isolate->factory()->boolean_map(); |
728 if (type->IsConstant()) { | 717 if (type->IsConstant()) { |
729 return handle( | 718 return handle( |
730 Handle<JSGlobalObject>::cast(type->AsConstant()->Value())->map()); | 719 Handle<JSGlobalObject>::cast(type->AsConstant()->Value())->map()); |
(...skipping 10 matching lines...) Expand all Loading... |
741 return T::Number(region); | 730 return T::Number(region); |
742 } else if (map->instance_type() == ODDBALL_TYPE) { | 731 } else if (map->instance_type() == ODDBALL_TYPE) { |
743 // The only oddballs that can be recorded in ICs are booleans. | 732 // The only oddballs that can be recorded in ICs are booleans. |
744 return T::Boolean(region); | 733 return T::Boolean(region); |
745 } else { | 734 } else { |
746 return T::Class(map, region); | 735 return T::Class(map, region); |
747 } | 736 } |
748 } | 737 } |
749 | 738 |
750 | 739 |
751 template | 740 template Type* IC::MapToType<Type>(Handle<Map> map, Zone* zone); |
752 Type* IC::MapToType<Type>(Handle<Map> map, Zone* zone); | |
753 | 741 |
754 | 742 |
755 template | 743 template Handle<HeapType> IC::MapToType<HeapType>(Handle<Map> map, |
756 Handle<HeapType> IC::MapToType<HeapType>(Handle<Map> map, Isolate* region); | 744 Isolate* region); |
757 | 745 |
758 | 746 |
759 void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) { | 747 void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) { |
760 DCHECK(handler->is_handler()); | 748 DCHECK(handler->is_handler()); |
761 Handle<Code> ic = PropertyICCompiler::ComputeMonomorphic( | 749 Handle<Code> ic = PropertyICCompiler::ComputeMonomorphic( |
762 kind(), name, receiver_type(), handler, extra_ic_state()); | 750 kind(), name, receiver_type(), handler, extra_ic_state()); |
763 set_target(*ic); | 751 set_target(*ic); |
764 } | 752 } |
765 | 753 |
766 | 754 |
767 void IC::CopyICToMegamorphicCache(Handle<Name> name) { | 755 void IC::CopyICToMegamorphicCache(Handle<Name> name) { |
768 TypeHandleList types; | 756 TypeHandleList types; |
769 CodeHandleList handlers; | 757 CodeHandleList handlers; |
770 TargetTypes(&types); | 758 TargetTypes(&types); |
771 if (!target()->FindHandlers(&handlers, types.length())) return; | 759 if (!target()->FindHandlers(&handlers, types.length())) return; |
772 for (int i = 0; i < types.length(); i++) { | 760 for (int i = 0; i < types.length(); i++) { |
773 UpdateMegamorphicCache(*types.at(i), *name, *handlers.at(i)); | 761 UpdateMegamorphicCache(*types.at(i), *name, *handlers.at(i)); |
774 } | 762 } |
775 } | 763 } |
776 | 764 |
777 | 765 |
778 bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) { | 766 bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) { |
779 if (source_map == NULL) return true; | 767 if (source_map == NULL) return true; |
780 if (target_map == NULL) return false; | 768 if (target_map == NULL) return false; |
781 ElementsKind target_elements_kind = target_map->elements_kind(); | 769 ElementsKind target_elements_kind = target_map->elements_kind(); |
782 bool more_general_transition = | 770 bool more_general_transition = IsMoreGeneralElementsKindTransition( |
783 IsMoreGeneralElementsKindTransition( | 771 source_map->elements_kind(), target_elements_kind); |
784 source_map->elements_kind(), target_elements_kind); | 772 Map* transitioned_map = |
785 Map* transitioned_map = more_general_transition | 773 more_general_transition |
786 ? source_map->LookupElementsTransitionMap(target_elements_kind) | 774 ? source_map->LookupElementsTransitionMap(target_elements_kind) |
787 : NULL; | 775 : NULL; |
788 | 776 |
789 return transitioned_map == target_map; | 777 return transitioned_map == target_map; |
790 } | 778 } |
791 | 779 |
792 | 780 |
793 void IC::PatchCache(Handle<Name> name, Handle<Code> code) { | 781 void IC::PatchCache(Handle<Name> name, Handle<Code> code) { |
794 switch (state()) { | 782 switch (state()) { |
795 case UNINITIALIZED: | 783 case UNINITIALIZED: |
796 case PREMONOMORPHIC: | 784 case PREMONOMORPHIC: |
797 UpdateMonomorphicIC(code, name); | 785 UpdateMonomorphicIC(code, name); |
798 break; | 786 break; |
799 case PROTOTYPE_FAILURE: | 787 case PROTOTYPE_FAILURE: |
800 case MONOMORPHIC: | 788 case MONOMORPHIC: |
801 case POLYMORPHIC: | 789 case POLYMORPHIC: |
802 if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) { | 790 if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) { |
803 if (UpdatePolymorphicIC(name, code)) break; | 791 if (UpdatePolymorphicIC(name, code)) break; |
804 CopyICToMegamorphicCache(name); | 792 CopyICToMegamorphicCache(name); |
805 } | 793 } |
806 set_target(*megamorphic_stub()); | 794 set_target(*megamorphic_stub()); |
807 // Fall through. | 795 // Fall through. |
808 case MEGAMORPHIC: | 796 case MEGAMORPHIC: |
809 UpdateMegamorphicCache(*receiver_type(), *name, *code); | 797 UpdateMegamorphicCache(*receiver_type(), *name, *code); |
810 break; | 798 break; |
811 case DEBUG_STUB: | 799 case DEBUG_STUB: |
812 break; | 800 break; |
813 case DEFAULT: | 801 case DEFAULT: |
814 case GENERIC: | 802 case GENERIC: |
815 UNREACHABLE(); | 803 UNREACHABLE(); |
816 break; | 804 break; |
817 } | 805 } |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1133 return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map); | 1121 return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map); |
1134 } | 1122 } |
1135 | 1123 |
1136 // The first time a receiver is seen that is a transitioned version of the | 1124 // The first time a receiver is seen that is a transitioned version of the |
1137 // previous monomorphic receiver type, assume the new ElementsKind is the | 1125 // previous monomorphic receiver type, assume the new ElementsKind is the |
1138 // monomorphic type. This benefits global arrays that only transition | 1126 // monomorphic type. This benefits global arrays that only transition |
1139 // once, and all call sites accessing them are faster if they remain | 1127 // once, and all call sites accessing them are faster if they remain |
1140 // monomorphic. If this optimistic assumption is not true, the IC will | 1128 // monomorphic. If this optimistic assumption is not true, the IC will |
1141 // miss again and it will become polymorphic and support both the | 1129 // miss again and it will become polymorphic and support both the |
1142 // untransitioned and transitioned maps. | 1130 // untransitioned and transitioned maps. |
1143 if (state() == MONOMORPHIC && | 1131 if (state() == MONOMORPHIC && IsMoreGeneralElementsKindTransition( |
1144 IsMoreGeneralElementsKindTransition( | 1132 target_receiver_maps.at(0)->elements_kind(), |
1145 target_receiver_maps.at(0)->elements_kind(), | 1133 receiver->GetElementsKind())) { |
1146 receiver->GetElementsKind())) { | |
1147 return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map); | 1134 return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map); |
1148 } | 1135 } |
1149 | 1136 |
1150 DCHECK(state() != GENERIC); | 1137 DCHECK(state() != GENERIC); |
1151 | 1138 |
1152 // Determine the list of receiver maps that this call site has seen, | 1139 // Determine the list of receiver maps that this call site has seen, |
1153 // adding the map that was just encountered. | 1140 // adding the map that was just encountered. |
1154 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) { | 1141 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) { |
1155 // If the miss wasn't due to an unseen map, a polymorphic stub | 1142 // If the miss wasn't due to an unseen map, a polymorphic stub |
1156 // won't help, use the generic stub. | 1143 // won't help, use the generic stub. |
(...skipping 10 matching lines...) Expand all Loading... |
1167 | 1154 |
1168 return PropertyICCompiler::ComputeKeyedLoadPolymorphic(&target_receiver_maps); | 1155 return PropertyICCompiler::ComputeKeyedLoadPolymorphic(&target_receiver_maps); |
1169 } | 1156 } |
1170 | 1157 |
1171 | 1158 |
1172 MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object, | 1159 MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object, |
1173 Handle<Object> key) { | 1160 Handle<Object> key) { |
1174 if (MigrateDeprecated(object)) { | 1161 if (MigrateDeprecated(object)) { |
1175 Handle<Object> result; | 1162 Handle<Object> result; |
1176 ASSIGN_RETURN_ON_EXCEPTION( | 1163 ASSIGN_RETURN_ON_EXCEPTION( |
1177 isolate(), | 1164 isolate(), result, Runtime::GetObjectProperty(isolate(), object, key), |
1178 result, | |
1179 Runtime::GetObjectProperty(isolate(), object, key), | |
1180 Object); | 1165 Object); |
1181 return result; | 1166 return result; |
1182 } | 1167 } |
1183 | 1168 |
1184 Handle<Object> load_handle; | 1169 Handle<Object> load_handle; |
1185 Handle<Code> stub = generic_stub(); | 1170 Handle<Code> stub = generic_stub(); |
1186 | 1171 |
1187 // Check for non-string values that can be converted into an | 1172 // Check for non-string values that can be converted into an |
1188 // internalized string directly or is representable as a smi. | 1173 // internalized string directly or is representable as a smi. |
1189 key = TryConvertKey(key, isolate()); | 1174 key = TryConvertKey(key, isolate()); |
1190 | 1175 |
1191 if (key->IsInternalizedString() || key->IsSymbol()) { | 1176 if (key->IsInternalizedString() || key->IsSymbol()) { |
1192 ASSIGN_RETURN_ON_EXCEPTION( | 1177 ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle, |
1193 isolate(), | 1178 LoadIC::Load(object, Handle<Name>::cast(key)), |
1194 load_handle, | 1179 Object); |
1195 LoadIC::Load(object, Handle<Name>::cast(key)), | |
1196 Object); | |
1197 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) { | 1180 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) { |
1198 if (object->IsString() && key->IsNumber()) { | 1181 if (object->IsString() && key->IsNumber()) { |
1199 if (state() == UNINITIALIZED) stub = string_stub(); | 1182 if (state() == UNINITIALIZED) stub = string_stub(); |
1200 } else if (object->IsJSObject()) { | 1183 } else if (object->IsJSObject()) { |
1201 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1184 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
1202 if (receiver->elements()->map() == | 1185 if (receiver->elements()->map() == |
1203 isolate()->heap()->sloppy_arguments_elements_map()) { | 1186 isolate()->heap()->sloppy_arguments_elements_map()) { |
1204 stub = sloppy_arguments_stub(); | 1187 stub = sloppy_arguments_stub(); |
1205 } else if (receiver->HasIndexedInterceptor()) { | 1188 } else if (receiver->HasIndexedInterceptor()) { |
1206 stub = indexed_interceptor_stub(); | 1189 stub = indexed_interceptor_stub(); |
1207 } else if (!Object::ToSmi(isolate(), key).is_null() && | 1190 } else if (!Object::ToSmi(isolate(), key).is_null() && |
1208 (!target().is_identical_to(sloppy_arguments_stub()))) { | 1191 (!target().is_identical_to(sloppy_arguments_stub()))) { |
1209 stub = LoadElementStub(receiver); | 1192 stub = LoadElementStub(receiver); |
1210 } | 1193 } |
1211 } | 1194 } |
1212 } | 1195 } |
1213 | 1196 |
1214 if (!is_target_set()) { | 1197 if (!is_target_set()) { |
1215 Code* generic = *generic_stub(); | 1198 Code* generic = *generic_stub(); |
1216 if (*stub == generic) { | 1199 if (*stub == generic) { |
1217 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic"); | 1200 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic"); |
1218 } | 1201 } |
1219 set_target(*stub); | 1202 set_target(*stub); |
1220 TRACE_IC("LoadIC", key); | 1203 TRACE_IC("LoadIC", key); |
1221 } | 1204 } |
1222 | 1205 |
1223 if (!load_handle.is_null()) return load_handle; | 1206 if (!load_handle.is_null()) return load_handle; |
1224 Handle<Object> result; | 1207 Handle<Object> result; |
1225 ASSIGN_RETURN_ON_EXCEPTION( | 1208 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, |
1226 isolate(), | 1209 Runtime::GetObjectProperty(isolate(), object, key), |
1227 result, | 1210 Object); |
1228 Runtime::GetObjectProperty(isolate(), object, key), | |
1229 Object); | |
1230 return result; | 1211 return result; |
1231 } | 1212 } |
1232 | 1213 |
1233 | 1214 |
1234 bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, | 1215 bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, |
1235 JSReceiver::StoreFromKeyed store_mode) { | 1216 JSReceiver::StoreFromKeyed store_mode) { |
1236 // Disable ICs for non-JSObjects for now. | 1217 // Disable ICs for non-JSObjects for now. |
1237 if (!it->GetReceiver()->IsJSObject()) return false; | 1218 if (!it->GetReceiver()->IsJSObject()) return false; |
1238 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); | 1219 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); |
1239 DCHECK(!receiver->map()->is_deprecated()); | 1220 DCHECK(!receiver->map()->is_deprecated()); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1281 it->PrepareTransitionToDataProperty(value, NONE, store_mode); | 1262 it->PrepareTransitionToDataProperty(value, NONE, store_mode); |
1282 return it->IsCacheableTransition(); | 1263 return it->IsCacheableTransition(); |
1283 } | 1264 } |
1284 } | 1265 } |
1285 | 1266 |
1286 it->PrepareTransitionToDataProperty(value, NONE, store_mode); | 1267 it->PrepareTransitionToDataProperty(value, NONE, store_mode); |
1287 return it->IsCacheableTransition(); | 1268 return it->IsCacheableTransition(); |
1288 } | 1269 } |
1289 | 1270 |
1290 | 1271 |
1291 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, | 1272 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, |
1292 Handle<Name> name, | |
1293 Handle<Object> value, | 1273 Handle<Object> value, |
1294 JSReceiver::StoreFromKeyed store_mode) { | 1274 JSReceiver::StoreFromKeyed store_mode) { |
1295 // TODO(verwaest): Let SetProperty do the migration, since storing a property | 1275 // TODO(verwaest): Let SetProperty do the migration, since storing a property |
1296 // might deprecate the current map again, if value does not fit. | 1276 // might deprecate the current map again, if value does not fit. |
1297 if (MigrateDeprecated(object) || object->IsJSProxy()) { | 1277 if (MigrateDeprecated(object) || object->IsJSProxy()) { |
1298 Handle<Object> result; | 1278 Handle<Object> result; |
1299 ASSIGN_RETURN_ON_EXCEPTION( | 1279 ASSIGN_RETURN_ON_EXCEPTION( |
1300 isolate(), result, | 1280 isolate(), result, |
1301 Object::SetProperty(object, name, value, strict_mode()), Object); | 1281 Object::SetProperty(object, name, value, strict_mode()), Object); |
1302 return result; | 1282 return result; |
1303 } | 1283 } |
1304 | 1284 |
1305 // If the object is undefined or null it's illegal to try to set any | 1285 // If the object is undefined or null it's illegal to try to set any |
1306 // properties on it; throw a TypeError in that case. | 1286 // properties on it; throw a TypeError in that case. |
1307 if (object->IsUndefined() || object->IsNull()) { | 1287 if (object->IsUndefined() || object->IsNull()) { |
1308 return TypeError("non_object_property_store", object, name); | 1288 return TypeError("non_object_property_store", object, name); |
1309 } | 1289 } |
1310 | 1290 |
1311 // Check if the given name is an array index. | 1291 // Check if the given name is an array index. |
1312 uint32_t index; | 1292 uint32_t index; |
1313 if (name->AsArrayIndex(&index)) { | 1293 if (name->AsArrayIndex(&index)) { |
1314 // Ignore other stores where the receiver is not a JSObject. | 1294 // Ignore other stores where the receiver is not a JSObject. |
1315 // TODO(1475): Must check prototype chains of object wrappers. | 1295 // TODO(1475): Must check prototype chains of object wrappers. |
1316 if (!object->IsJSObject()) return value; | 1296 if (!object->IsJSObject()) return value; |
1317 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1297 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
1318 | 1298 |
1319 Handle<Object> result; | 1299 Handle<Object> result; |
1320 ASSIGN_RETURN_ON_EXCEPTION( | 1300 ASSIGN_RETURN_ON_EXCEPTION( |
1321 isolate(), | 1301 isolate(), result, |
1322 result, | |
1323 JSObject::SetElement(receiver, index, value, NONE, strict_mode()), | 1302 JSObject::SetElement(receiver, index, value, NONE, strict_mode()), |
1324 Object); | 1303 Object); |
1325 return value; | 1304 return value; |
1326 } | 1305 } |
1327 | 1306 |
1328 // Observed objects are always modified through the runtime. | 1307 // Observed objects are always modified through the runtime. |
1329 if (object->IsHeapObject() && | 1308 if (object->IsHeapObject() && |
1330 Handle<HeapObject>::cast(object)->map()->is_observed()) { | 1309 Handle<HeapObject>::cast(object)->map()->is_observed()) { |
1331 Handle<Object> result; | 1310 Handle<Object> result; |
1332 ASSIGN_RETURN_ON_EXCEPTION( | 1311 ASSIGN_RETURN_ON_EXCEPTION( |
(...skipping 15 matching lines...) Expand all Loading... |
1348 } | 1327 } |
1349 | 1328 |
1350 | 1329 |
1351 OStream& operator<<(OStream& os, const CallIC::State& s) { | 1330 OStream& operator<<(OStream& os, const CallIC::State& s) { |
1352 return os << "(args(" << s.arg_count() << "), " | 1331 return os << "(args(" << s.arg_count() << "), " |
1353 << (s.call_type() == CallIC::METHOD ? "METHOD" : "FUNCTION") | 1332 << (s.call_type() == CallIC::METHOD ? "METHOD" : "FUNCTION") |
1354 << ", "; | 1333 << ", "; |
1355 } | 1334 } |
1356 | 1335 |
1357 | 1336 |
1358 Handle<Code> CallIC::initialize_stub(Isolate* isolate, | 1337 Handle<Code> CallIC::initialize_stub(Isolate* isolate, int argc, |
1359 int argc, | |
1360 CallType call_type) { | 1338 CallType call_type) { |
1361 CallICStub stub(isolate, State(argc, call_type)); | 1339 CallICStub stub(isolate, State(argc, call_type)); |
1362 Handle<Code> code = stub.GetCode(); | 1340 Handle<Code> code = stub.GetCode(); |
1363 return code; | 1341 return code; |
1364 } | 1342 } |
1365 | 1343 |
1366 | 1344 |
1367 Handle<Code> StoreIC::initialize_stub(Isolate* isolate, | 1345 Handle<Code> StoreIC::initialize_stub(Isolate* isolate, |
1368 StrictMode strict_mode) { | 1346 StrictMode strict_mode) { |
1369 ExtraICState extra_state = ComputeExtraICState(strict_mode); | 1347 ExtraICState extra_state = ComputeExtraICState(strict_mode); |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1618 int external_arrays = 0; | 1596 int external_arrays = 0; |
1619 for (int i = 0; i < target_receiver_maps.length(); ++i) { | 1597 for (int i = 0; i < target_receiver_maps.length(); ++i) { |
1620 if (target_receiver_maps[i]->has_external_array_elements() || | 1598 if (target_receiver_maps[i]->has_external_array_elements() || |
1621 target_receiver_maps[i]->has_fixed_typed_array_elements()) { | 1599 target_receiver_maps[i]->has_fixed_typed_array_elements()) { |
1622 external_arrays++; | 1600 external_arrays++; |
1623 } | 1601 } |
1624 } | 1602 } |
1625 if (external_arrays != 0 && | 1603 if (external_arrays != 0 && |
1626 external_arrays != target_receiver_maps.length()) { | 1604 external_arrays != target_receiver_maps.length()) { |
1627 TRACE_GENERIC_IC(isolate(), "KeyedIC", | 1605 TRACE_GENERIC_IC(isolate(), "KeyedIC", |
1628 "unsupported combination of external and normal arrays"); | 1606 "unsupported combination of external and normal arrays"); |
1629 return generic_stub(); | 1607 return generic_stub(); |
1630 } | 1608 } |
1631 } | 1609 } |
1632 | 1610 |
1633 return PropertyICCompiler::ComputeKeyedStorePolymorphic( | 1611 return PropertyICCompiler::ComputeKeyedStorePolymorphic( |
1634 &target_receiver_maps, store_mode, strict_mode()); | 1612 &target_receiver_maps, store_mode, strict_mode()); |
1635 } | 1613 } |
1636 | 1614 |
1637 | 1615 |
1638 Handle<Map> KeyedStoreIC::ComputeTransitionedMap( | 1616 Handle<Map> KeyedStoreIC::ComputeTransitionedMap( |
1639 Handle<Map> map, | 1617 Handle<Map> map, KeyedAccessStoreMode store_mode) { |
1640 KeyedAccessStoreMode store_mode) { | |
1641 switch (store_mode) { | 1618 switch (store_mode) { |
1642 case STORE_TRANSITION_SMI_TO_OBJECT: | 1619 case STORE_TRANSITION_SMI_TO_OBJECT: |
1643 case STORE_TRANSITION_DOUBLE_TO_OBJECT: | 1620 case STORE_TRANSITION_DOUBLE_TO_OBJECT: |
1644 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT: | 1621 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT: |
1645 case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT: | 1622 case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT: |
1646 return Map::TransitionElementsTo(map, FAST_ELEMENTS); | 1623 return Map::TransitionElementsTo(map, FAST_ELEMENTS); |
1647 case STORE_TRANSITION_SMI_TO_DOUBLE: | 1624 case STORE_TRANSITION_SMI_TO_DOUBLE: |
1648 case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE: | 1625 case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE: |
1649 return Map::TransitionElementsTo(map, FAST_DOUBLE_ELEMENTS); | 1626 return Map::TransitionElementsTo(map, FAST_DOUBLE_ELEMENTS); |
1650 case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT: | 1627 case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT: |
1651 case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT: | 1628 case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT: |
1652 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT: | 1629 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT: |
1653 case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT: | 1630 case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT: |
1654 return Map::TransitionElementsTo(map, FAST_HOLEY_ELEMENTS); | 1631 return Map::TransitionElementsTo(map, FAST_HOLEY_ELEMENTS); |
1655 case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE: | 1632 case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE: |
1656 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE: | 1633 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE: |
1657 return Map::TransitionElementsTo(map, FAST_HOLEY_DOUBLE_ELEMENTS); | 1634 return Map::TransitionElementsTo(map, FAST_HOLEY_DOUBLE_ELEMENTS); |
1658 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS: | 1635 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS: |
1659 DCHECK(map->has_external_array_elements()); | 1636 DCHECK(map->has_external_array_elements()); |
1660 // Fall through | 1637 // Fall through |
1661 case STORE_NO_TRANSITION_HANDLE_COW: | 1638 case STORE_NO_TRANSITION_HANDLE_COW: |
1662 case STANDARD_STORE: | 1639 case STANDARD_STORE: |
1663 case STORE_AND_GROW_NO_TRANSITION: | 1640 case STORE_AND_GROW_NO_TRANSITION: |
1664 return map; | 1641 return map; |
1665 } | 1642 } |
1666 UNREACHABLE(); | 1643 UNREACHABLE(); |
1667 return MaybeHandle<Map>().ToHandleChecked(); | 1644 return MaybeHandle<Map>().ToHandleChecked(); |
1668 } | 1645 } |
1669 | 1646 |
1670 | 1647 |
1671 bool IsOutOfBoundsAccess(Handle<JSObject> receiver, | 1648 bool IsOutOfBoundsAccess(Handle<JSObject> receiver, int index) { |
1672 int index) { | |
1673 if (receiver->IsJSArray()) { | 1649 if (receiver->IsJSArray()) { |
1674 return JSArray::cast(*receiver)->length()->IsSmi() && | 1650 return JSArray::cast(*receiver)->length()->IsSmi() && |
1675 index >= Smi::cast(JSArray::cast(*receiver)->length())->value(); | 1651 index >= Smi::cast(JSArray::cast(*receiver)->length())->value(); |
1676 } | 1652 } |
1677 return index >= receiver->elements()->length(); | 1653 return index >= receiver->elements()->length(); |
1678 } | 1654 } |
1679 | 1655 |
1680 | 1656 |
1681 KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver, | 1657 KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver, |
1682 Handle<Object> key, | 1658 Handle<Object> key, |
1683 Handle<Object> value) { | 1659 Handle<Object> value) { |
1684 Handle<Smi> smi_key = Object::ToSmi(isolate(), key).ToHandleChecked(); | 1660 Handle<Smi> smi_key = Object::ToSmi(isolate(), key).ToHandleChecked(); |
1685 int index = smi_key->value(); | 1661 int index = smi_key->value(); |
1686 bool oob_access = IsOutOfBoundsAccess(receiver, index); | 1662 bool oob_access = IsOutOfBoundsAccess(receiver, index); |
1687 // Don't consider this a growing store if the store would send the receiver to | 1663 // Don't consider this a growing store if the store would send the receiver to |
1688 // dictionary mode. | 1664 // dictionary mode. |
1689 bool allow_growth = receiver->IsJSArray() && oob_access && | 1665 bool allow_growth = receiver->IsJSArray() && oob_access && |
1690 !receiver->WouldConvertToSlowElements(key); | 1666 !receiver->WouldConvertToSlowElements(key); |
1691 if (allow_growth) { | 1667 if (allow_growth) { |
1692 // Handle growing array in stub if necessary. | 1668 // Handle growing array in stub if necessary. |
1693 if (receiver->HasFastSmiElements()) { | 1669 if (receiver->HasFastSmiElements()) { |
1694 if (value->IsHeapNumber()) { | 1670 if (value->IsHeapNumber()) { |
1695 if (receiver->HasFastHoleyElements()) { | 1671 if (receiver->HasFastHoleyElements()) { |
1696 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE; | 1672 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE; |
1697 } else { | 1673 } else { |
1698 return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE; | 1674 return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE; |
1699 } | 1675 } |
1700 } | 1676 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1755 | 1731 |
1756 | 1732 |
1757 MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, | 1733 MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, |
1758 Handle<Object> key, | 1734 Handle<Object> key, |
1759 Handle<Object> value) { | 1735 Handle<Object> value) { |
1760 // TODO(verwaest): Let SetProperty do the migration, since storing a property | 1736 // TODO(verwaest): Let SetProperty do the migration, since storing a property |
1761 // might deprecate the current map again, if value does not fit. | 1737 // might deprecate the current map again, if value does not fit. |
1762 if (MigrateDeprecated(object)) { | 1738 if (MigrateDeprecated(object)) { |
1763 Handle<Object> result; | 1739 Handle<Object> result; |
1764 ASSIGN_RETURN_ON_EXCEPTION( | 1740 ASSIGN_RETURN_ON_EXCEPTION( |
1765 isolate(), | 1741 isolate(), result, Runtime::SetObjectProperty(isolate(), object, key, |
1766 result, | 1742 value, strict_mode()), |
1767 Runtime::SetObjectProperty( | |
1768 isolate(), object, key, value, strict_mode()), | |
1769 Object); | 1743 Object); |
1770 return result; | 1744 return result; |
1771 } | 1745 } |
1772 | 1746 |
1773 // Check for non-string values that can be converted into an | 1747 // Check for non-string values that can be converted into an |
1774 // internalized string directly or is representable as a smi. | 1748 // internalized string directly or is representable as a smi. |
1775 key = TryConvertKey(key, isolate()); | 1749 key = TryConvertKey(key, isolate()); |
1776 | 1750 |
1777 Handle<Object> store_handle; | 1751 Handle<Object> store_handle; |
1778 Handle<Code> stub = generic_stub(); | 1752 Handle<Code> stub = generic_stub(); |
1779 | 1753 |
1780 if (key->IsInternalizedString()) { | 1754 if (key->IsInternalizedString()) { |
1781 ASSIGN_RETURN_ON_EXCEPTION( | 1755 ASSIGN_RETURN_ON_EXCEPTION( |
1782 isolate(), | 1756 isolate(), store_handle, |
1783 store_handle, | 1757 StoreIC::Store(object, Handle<String>::cast(key), value, |
1784 StoreIC::Store(object, | |
1785 Handle<String>::cast(key), | |
1786 value, | |
1787 JSReceiver::MAY_BE_STORE_FROM_KEYED), | 1758 JSReceiver::MAY_BE_STORE_FROM_KEYED), |
1788 Object); | 1759 Object); |
1789 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic"); | 1760 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic"); |
1790 set_target(*stub); | 1761 set_target(*stub); |
1791 return store_handle; | 1762 return store_handle; |
1792 } | 1763 } |
1793 | 1764 |
1794 bool use_ic = | 1765 bool use_ic = |
1795 FLAG_use_ic && !object->IsStringWrapper() && | 1766 FLAG_use_ic && !object->IsStringWrapper() && |
1796 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy() && | 1767 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy() && |
(...skipping 26 matching lines...) Expand all Loading... |
1823 if (!(receiver->map()->DictionaryElementsInPrototypeChainOnly())) { | 1794 if (!(receiver->map()->DictionaryElementsInPrototypeChainOnly())) { |
1824 KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value); | 1795 KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value); |
1825 stub = StoreElementStub(receiver, store_mode); | 1796 stub = StoreElementStub(receiver, store_mode); |
1826 } | 1797 } |
1827 } | 1798 } |
1828 } | 1799 } |
1829 } | 1800 } |
1830 | 1801 |
1831 if (store_handle.is_null()) { | 1802 if (store_handle.is_null()) { |
1832 ASSIGN_RETURN_ON_EXCEPTION( | 1803 ASSIGN_RETURN_ON_EXCEPTION( |
1833 isolate(), | 1804 isolate(), store_handle, |
1834 store_handle, | 1805 Runtime::SetObjectProperty(isolate(), object, key, value, |
1835 Runtime::SetObjectProperty( | 1806 strict_mode()), |
1836 isolate(), object, key, value, strict_mode()), | |
1837 Object); | 1807 Object); |
1838 } | 1808 } |
1839 | 1809 |
1840 DCHECK(!is_target_set()); | 1810 DCHECK(!is_target_set()); |
1841 Code* generic = *generic_stub(); | 1811 Code* generic = *generic_stub(); |
1842 if (*stub == generic) { | 1812 if (*stub == generic) { |
1843 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic"); | 1813 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic"); |
1844 } | 1814 } |
1845 DCHECK(!stub.is_null()); | 1815 DCHECK(!stub.is_null()); |
1846 set_target(*stub); | 1816 set_target(*stub); |
1847 TRACE_IC("StoreIC", key); | 1817 TRACE_IC("StoreIC", key); |
1848 | 1818 |
1849 return store_handle; | 1819 return store_handle; |
1850 } | 1820 } |
1851 | 1821 |
1852 | 1822 |
1853 CallIC::State::State(ExtraICState extra_ic_state) | 1823 CallIC::State::State(ExtraICState extra_ic_state) |
1854 : argc_(ArgcBits::decode(extra_ic_state)), | 1824 : argc_(ArgcBits::decode(extra_ic_state)), |
1855 call_type_(CallTypeBits::decode(extra_ic_state)) { | 1825 call_type_(CallTypeBits::decode(extra_ic_state)) {} |
1856 } | |
1857 | 1826 |
1858 | 1827 |
1859 ExtraICState CallIC::State::GetExtraICState() const { | 1828 ExtraICState CallIC::State::GetExtraICState() const { |
1860 ExtraICState extra_ic_state = | 1829 ExtraICState extra_ic_state = |
1861 ArgcBits::encode(argc_) | | 1830 ArgcBits::encode(argc_) | CallTypeBits::encode(call_type_); |
1862 CallTypeBits::encode(call_type_); | |
1863 return extra_ic_state; | 1831 return extra_ic_state; |
1864 } | 1832 } |
1865 | 1833 |
1866 | 1834 |
1867 bool CallIC::DoCustomHandler(Handle<Object> receiver, | 1835 bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function, |
1868 Handle<Object> function, | 1836 Handle<FixedArray> vector, Handle<Smi> slot, |
1869 Handle<FixedArray> vector, | |
1870 Handle<Smi> slot, | |
1871 const State& state) { | 1837 const State& state) { |
1872 DCHECK(FLAG_use_ic && function->IsJSFunction()); | 1838 DCHECK(FLAG_use_ic && function->IsJSFunction()); |
1873 | 1839 |
1874 // Are we the array function? | 1840 // Are we the array function? |
1875 Handle<JSFunction> array_function = Handle<JSFunction>( | 1841 Handle<JSFunction> array_function = |
1876 isolate()->native_context()->array_function()); | 1842 Handle<JSFunction>(isolate()->native_context()->array_function()); |
1877 if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) { | 1843 if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) { |
1878 // Alter the slot. | 1844 // Alter the slot. |
1879 IC::State old_state = FeedbackToState(vector, slot); | 1845 IC::State old_state = FeedbackToState(vector, slot); |
1880 Object* feedback = vector->get(slot->value()); | 1846 Object* feedback = vector->get(slot->value()); |
1881 if (!feedback->IsAllocationSite()) { | 1847 if (!feedback->IsAllocationSite()) { |
1882 Handle<AllocationSite> new_site = | 1848 Handle<AllocationSite> new_site = |
1883 isolate()->factory()->NewAllocationSite(); | 1849 isolate()->factory()->NewAllocationSite(); |
1884 vector->set(slot->value(), *new_site); | 1850 vector->set(slot->value(), *new_site); |
1885 } | 1851 } |
1886 | 1852 |
(...skipping 13 matching lines...) Expand all Loading... |
1900 return false; | 1866 return false; |
1901 } | 1867 } |
1902 | 1868 |
1903 | 1869 |
1904 void CallIC::PatchMegamorphic(Handle<Object> function, | 1870 void CallIC::PatchMegamorphic(Handle<Object> function, |
1905 Handle<FixedArray> vector, Handle<Smi> slot) { | 1871 Handle<FixedArray> vector, Handle<Smi> slot) { |
1906 State state(target()->extra_ic_state()); | 1872 State state(target()->extra_ic_state()); |
1907 IC::State old_state = FeedbackToState(vector, slot); | 1873 IC::State old_state = FeedbackToState(vector, slot); |
1908 | 1874 |
1909 // We are going generic. | 1875 // We are going generic. |
1910 vector->set(slot->value(), | 1876 vector->set(slot->value(), *TypeFeedbackInfo::MegamorphicSentinel(isolate()), |
1911 *TypeFeedbackInfo::MegamorphicSentinel(isolate()), | |
1912 SKIP_WRITE_BARRIER); | 1877 SKIP_WRITE_BARRIER); |
1913 | 1878 |
1914 CallICStub stub(isolate(), state); | 1879 CallICStub stub(isolate(), state); |
1915 Handle<Code> code = stub.GetCode(); | 1880 Handle<Code> code = stub.GetCode(); |
1916 set_target(*code); | 1881 set_target(*code); |
1917 | 1882 |
1918 Handle<Object> name = isolate()->factory()->empty_string(); | 1883 Handle<Object> name = isolate()->factory()->empty_string(); |
1919 if (function->IsJSFunction()) { | 1884 if (function->IsJSFunction()) { |
1920 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function); | 1885 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function); |
1921 name = handle(js_function->shared()->name(), isolate()); | 1886 name = handle(js_function->shared()->name(), isolate()); |
1922 } | 1887 } |
1923 | 1888 |
1924 IC::State new_state = FeedbackToState(vector, slot); | 1889 IC::State new_state = FeedbackToState(vector, slot); |
1925 OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true); | 1890 OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true); |
1926 TRACE_VECTOR_IC("CallIC", name, old_state, new_state); | 1891 TRACE_VECTOR_IC("CallIC", name, old_state, new_state); |
1927 } | 1892 } |
1928 | 1893 |
1929 | 1894 |
1930 void CallIC::HandleMiss(Handle<Object> receiver, | 1895 void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function, |
1931 Handle<Object> function, | 1896 Handle<FixedArray> vector, Handle<Smi> slot) { |
1932 Handle<FixedArray> vector, | |
1933 Handle<Smi> slot) { | |
1934 State state(target()->extra_ic_state()); | 1897 State state(target()->extra_ic_state()); |
1935 IC::State old_state = FeedbackToState(vector, slot); | 1898 IC::State old_state = FeedbackToState(vector, slot); |
1936 Handle<Object> name = isolate()->factory()->empty_string(); | 1899 Handle<Object> name = isolate()->factory()->empty_string(); |
1937 Object* feedback = vector->get(slot->value()); | 1900 Object* feedback = vector->get(slot->value()); |
1938 | 1901 |
1939 // Hand-coded MISS handling is easier if CallIC slots don't contain smis. | 1902 // Hand-coded MISS handling is easier if CallIC slots don't contain smis. |
1940 DCHECK(!feedback->IsSmi()); | 1903 DCHECK(!feedback->IsSmi()); |
1941 | 1904 |
1942 if (feedback->IsJSFunction() || !function->IsJSFunction()) { | 1905 if (feedback->IsJSFunction() || !function->IsJSFunction()) { |
1943 // We are going generic. | 1906 // We are going generic. |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2058 RUNTIME_FUNCTION(StoreIC_Miss) { | 2021 RUNTIME_FUNCTION(StoreIC_Miss) { |
2059 TimerEventScope<TimerEventIcMiss> timer(isolate); | 2022 TimerEventScope<TimerEventIcMiss> timer(isolate); |
2060 HandleScope scope(isolate); | 2023 HandleScope scope(isolate); |
2061 DCHECK(args.length() == 3); | 2024 DCHECK(args.length() == 3); |
2062 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2025 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
2063 Handle<Object> receiver = args.at<Object>(0); | 2026 Handle<Object> receiver = args.at<Object>(0); |
2064 Handle<String> key = args.at<String>(1); | 2027 Handle<String> key = args.at<String>(1); |
2065 ic.UpdateState(receiver, key); | 2028 ic.UpdateState(receiver, key); |
2066 Handle<Object> result; | 2029 Handle<Object> result; |
2067 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 2030 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
2068 isolate, | 2031 isolate, result, ic.Store(receiver, key, args.at<Object>(2))); |
2069 result, | |
2070 ic.Store(receiver, key, args.at<Object>(2))); | |
2071 return *result; | 2032 return *result; |
2072 } | 2033 } |
2073 | 2034 |
2074 | 2035 |
2075 RUNTIME_FUNCTION(StoreIC_MissFromStubFailure) { | 2036 RUNTIME_FUNCTION(StoreIC_MissFromStubFailure) { |
2076 TimerEventScope<TimerEventIcMiss> timer(isolate); | 2037 TimerEventScope<TimerEventIcMiss> timer(isolate); |
2077 HandleScope scope(isolate); | 2038 HandleScope scope(isolate); |
2078 DCHECK(args.length() == 3); | 2039 DCHECK(args.length() == 3); |
2079 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate); | 2040 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate); |
2080 Handle<Object> receiver = args.at<Object>(0); | 2041 Handle<Object> receiver = args.at<Object>(0); |
2081 Handle<String> key = args.at<String>(1); | 2042 Handle<String> key = args.at<String>(1); |
2082 ic.UpdateState(receiver, key); | 2043 ic.UpdateState(receiver, key); |
2083 Handle<Object> result; | 2044 Handle<Object> result; |
2084 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 2045 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
2085 isolate, | 2046 isolate, result, ic.Store(receiver, key, args.at<Object>(2))); |
2086 result, | |
2087 ic.Store(receiver, key, args.at<Object>(2))); | |
2088 return *result; | 2047 return *result; |
2089 } | 2048 } |
2090 | 2049 |
2091 | 2050 |
2092 // Extend storage is called in a store inline cache when | 2051 // Extend storage is called in a store inline cache when |
2093 // it is necessary to extend the properties array of a | 2052 // it is necessary to extend the properties array of a |
2094 // JSObject. | 2053 // JSObject. |
2095 RUNTIME_FUNCTION(SharedStoreIC_ExtendStorage) { | 2054 RUNTIME_FUNCTION(SharedStoreIC_ExtendStorage) { |
2096 TimerEventScope<TimerEventIcMiss> timer(isolate); | 2055 TimerEventScope<TimerEventIcMiss> timer(isolate); |
2097 HandleScope shs(isolate); | 2056 HandleScope shs(isolate); |
(...skipping 19 matching lines...) Expand all Loading... |
2117 RUNTIME_FUNCTION(KeyedStoreIC_Miss) { | 2076 RUNTIME_FUNCTION(KeyedStoreIC_Miss) { |
2118 TimerEventScope<TimerEventIcMiss> timer(isolate); | 2077 TimerEventScope<TimerEventIcMiss> timer(isolate); |
2119 HandleScope scope(isolate); | 2078 HandleScope scope(isolate); |
2120 DCHECK(args.length() == 3); | 2079 DCHECK(args.length() == 3); |
2121 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2080 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
2122 Handle<Object> receiver = args.at<Object>(0); | 2081 Handle<Object> receiver = args.at<Object>(0); |
2123 Handle<Object> key = args.at<Object>(1); | 2082 Handle<Object> key = args.at<Object>(1); |
2124 ic.UpdateState(receiver, key); | 2083 ic.UpdateState(receiver, key); |
2125 Handle<Object> result; | 2084 Handle<Object> result; |
2126 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 2085 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
2127 isolate, | 2086 isolate, result, ic.Store(receiver, key, args.at<Object>(2))); |
2128 result, | |
2129 ic.Store(receiver, key, args.at<Object>(2))); | |
2130 return *result; | 2087 return *result; |
2131 } | 2088 } |
2132 | 2089 |
2133 | 2090 |
2134 RUNTIME_FUNCTION(KeyedStoreIC_MissFromStubFailure) { | 2091 RUNTIME_FUNCTION(KeyedStoreIC_MissFromStubFailure) { |
2135 TimerEventScope<TimerEventIcMiss> timer(isolate); | 2092 TimerEventScope<TimerEventIcMiss> timer(isolate); |
2136 HandleScope scope(isolate); | 2093 HandleScope scope(isolate); |
2137 DCHECK(args.length() == 3); | 2094 DCHECK(args.length() == 3); |
2138 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); | 2095 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); |
2139 Handle<Object> receiver = args.at<Object>(0); | 2096 Handle<Object> receiver = args.at<Object>(0); |
2140 Handle<Object> key = args.at<Object>(1); | 2097 Handle<Object> key = args.at<Object>(1); |
2141 ic.UpdateState(receiver, key); | 2098 ic.UpdateState(receiver, key); |
2142 Handle<Object> result; | 2099 Handle<Object> result; |
2143 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 2100 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
2144 isolate, | 2101 isolate, result, ic.Store(receiver, key, args.at<Object>(2))); |
2145 result, | |
2146 ic.Store(receiver, key, args.at<Object>(2))); | |
2147 return *result; | 2102 return *result; |
2148 } | 2103 } |
2149 | 2104 |
2150 | 2105 |
2151 RUNTIME_FUNCTION(StoreIC_Slow) { | 2106 RUNTIME_FUNCTION(StoreIC_Slow) { |
2152 HandleScope scope(isolate); | 2107 HandleScope scope(isolate); |
2153 DCHECK(args.length() == 3); | 2108 DCHECK(args.length() == 3); |
2154 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2109 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
2155 Handle<Object> object = args.at<Object>(0); | 2110 Handle<Object> object = args.at<Object>(0); |
2156 Handle<Object> key = args.at<Object>(1); | 2111 Handle<Object> key = args.at<Object>(1); |
2157 Handle<Object> value = args.at<Object>(2); | 2112 Handle<Object> value = args.at<Object>(2); |
2158 StrictMode strict_mode = ic.strict_mode(); | 2113 StrictMode strict_mode = ic.strict_mode(); |
2159 Handle<Object> result; | 2114 Handle<Object> result; |
2160 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 2115 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
2161 isolate, result, | 2116 isolate, result, |
2162 Runtime::SetObjectProperty( | 2117 Runtime::SetObjectProperty(isolate, object, key, value, strict_mode)); |
2163 isolate, object, key, value, strict_mode)); | |
2164 return *result; | 2118 return *result; |
2165 } | 2119 } |
2166 | 2120 |
2167 | 2121 |
2168 RUNTIME_FUNCTION(KeyedStoreIC_Slow) { | 2122 RUNTIME_FUNCTION(KeyedStoreIC_Slow) { |
2169 HandleScope scope(isolate); | 2123 HandleScope scope(isolate); |
2170 DCHECK(args.length() == 3); | 2124 DCHECK(args.length() == 3); |
2171 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2125 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
2172 Handle<Object> object = args.at<Object>(0); | 2126 Handle<Object> object = args.at<Object>(0); |
2173 Handle<Object> key = args.at<Object>(1); | 2127 Handle<Object> key = args.at<Object>(1); |
2174 Handle<Object> value = args.at<Object>(2); | 2128 Handle<Object> value = args.at<Object>(2); |
2175 StrictMode strict_mode = ic.strict_mode(); | 2129 StrictMode strict_mode = ic.strict_mode(); |
2176 Handle<Object> result; | 2130 Handle<Object> result; |
2177 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 2131 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
2178 isolate, result, | 2132 isolate, result, |
2179 Runtime::SetObjectProperty( | 2133 Runtime::SetObjectProperty(isolate, object, key, value, strict_mode)); |
2180 isolate, object, key, value, strict_mode)); | |
2181 return *result; | 2134 return *result; |
2182 } | 2135 } |
2183 | 2136 |
2184 | 2137 |
2185 RUNTIME_FUNCTION(ElementsTransitionAndStoreIC_Miss) { | 2138 RUNTIME_FUNCTION(ElementsTransitionAndStoreIC_Miss) { |
2186 TimerEventScope<TimerEventIcMiss> timer(isolate); | 2139 TimerEventScope<TimerEventIcMiss> timer(isolate); |
2187 HandleScope scope(isolate); | 2140 HandleScope scope(isolate); |
2188 DCHECK(args.length() == 4); | 2141 DCHECK(args.length() == 4); |
2189 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); | 2142 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); |
2190 Handle<Object> value = args.at<Object>(0); | 2143 Handle<Object> value = args.at<Object>(0); |
2191 Handle<Map> map = args.at<Map>(1); | 2144 Handle<Map> map = args.at<Map>(1); |
2192 Handle<Object> key = args.at<Object>(2); | 2145 Handle<Object> key = args.at<Object>(2); |
2193 Handle<Object> object = args.at<Object>(3); | 2146 Handle<Object> object = args.at<Object>(3); |
2194 StrictMode strict_mode = ic.strict_mode(); | 2147 StrictMode strict_mode = ic.strict_mode(); |
2195 if (object->IsJSObject()) { | 2148 if (object->IsJSObject()) { |
2196 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), | 2149 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), |
2197 map->elements_kind()); | 2150 map->elements_kind()); |
2198 } | 2151 } |
2199 Handle<Object> result; | 2152 Handle<Object> result; |
2200 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 2153 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
2201 isolate, result, | 2154 isolate, result, |
2202 Runtime::SetObjectProperty( | 2155 Runtime::SetObjectProperty(isolate, object, key, value, strict_mode)); |
2203 isolate, object, key, value, strict_mode)); | |
2204 return *result; | 2156 return *result; |
2205 } | 2157 } |
2206 | 2158 |
2207 | 2159 |
2208 BinaryOpIC::State::State(Isolate* isolate, ExtraICState extra_ic_state) | 2160 BinaryOpIC::State::State(Isolate* isolate, ExtraICState extra_ic_state) |
2209 : isolate_(isolate) { | 2161 : isolate_(isolate) { |
2210 op_ = static_cast<Token::Value>( | 2162 op_ = |
2211 FIRST_TOKEN + OpField::decode(extra_ic_state)); | 2163 static_cast<Token::Value>(FIRST_TOKEN + OpField::decode(extra_ic_state)); |
2212 mode_ = OverwriteModeField::decode(extra_ic_state); | 2164 mode_ = OverwriteModeField::decode(extra_ic_state); |
2213 fixed_right_arg_ = Maybe<int>( | 2165 fixed_right_arg_ = |
2214 HasFixedRightArgField::decode(extra_ic_state), | 2166 Maybe<int>(HasFixedRightArgField::decode(extra_ic_state), |
2215 1 << FixedRightArgValueField::decode(extra_ic_state)); | 2167 1 << FixedRightArgValueField::decode(extra_ic_state)); |
2216 left_kind_ = LeftKindField::decode(extra_ic_state); | 2168 left_kind_ = LeftKindField::decode(extra_ic_state); |
2217 if (fixed_right_arg_.has_value) { | 2169 if (fixed_right_arg_.has_value) { |
2218 right_kind_ = Smi::IsValid(fixed_right_arg_.value) ? SMI : INT32; | 2170 right_kind_ = Smi::IsValid(fixed_right_arg_.value) ? SMI : INT32; |
2219 } else { | 2171 } else { |
2220 right_kind_ = RightKindField::decode(extra_ic_state); | 2172 right_kind_ = RightKindField::decode(extra_ic_state); |
2221 } | 2173 } |
2222 result_kind_ = ResultKindField::decode(extra_ic_state); | 2174 result_kind_ = ResultKindField::decode(extra_ic_state); |
2223 DCHECK_LE(FIRST_TOKEN, op_); | 2175 DCHECK_LE(FIRST_TOKEN, op_); |
2224 DCHECK_LE(op_, LAST_TOKEN); | 2176 DCHECK_LE(op_, LAST_TOKEN); |
2225 } | 2177 } |
2226 | 2178 |
2227 | 2179 |
2228 ExtraICState BinaryOpIC::State::GetExtraICState() const { | 2180 ExtraICState BinaryOpIC::State::GetExtraICState() const { |
2229 ExtraICState extra_ic_state = | 2181 ExtraICState extra_ic_state = |
2230 OpField::encode(op_ - FIRST_TOKEN) | | 2182 OpField::encode(op_ - FIRST_TOKEN) | OverwriteModeField::encode(mode_) | |
2231 OverwriteModeField::encode(mode_) | | |
2232 LeftKindField::encode(left_kind_) | | 2183 LeftKindField::encode(left_kind_) | |
2233 ResultKindField::encode(result_kind_) | | 2184 ResultKindField::encode(result_kind_) | |
2234 HasFixedRightArgField::encode(fixed_right_arg_.has_value); | 2185 HasFixedRightArgField::encode(fixed_right_arg_.has_value); |
2235 if (fixed_right_arg_.has_value) { | 2186 if (fixed_right_arg_.has_value) { |
2236 extra_ic_state = FixedRightArgValueField::update( | 2187 extra_ic_state = FixedRightArgValueField::update( |
2237 extra_ic_state, WhichPowerOf2(fixed_right_arg_.value)); | 2188 extra_ic_state, WhichPowerOf2(fixed_right_arg_.value)); |
2238 } else { | 2189 } else { |
2239 extra_ic_state = RightKindField::update(extra_ic_state, right_kind_); | 2190 extra_ic_state = RightKindField::update(extra_ic_state, right_kind_); |
2240 } | 2191 } |
2241 return extra_ic_state; | 2192 return extra_ic_state; |
2242 } | 2193 } |
2243 | 2194 |
2244 | 2195 |
2245 // static | 2196 // static |
2246 void BinaryOpIC::State::GenerateAheadOfTime( | 2197 void BinaryOpIC::State::GenerateAheadOfTime(Isolate* isolate, |
2247 Isolate* isolate, void (*Generate)(Isolate*, const State&)) { | 2198 void (*Generate)(Isolate*, |
2248 // TODO(olivf) We should investigate why adding stubs to the snapshot is so | 2199 const State&)) { |
2249 // expensive at runtime. When solved we should be able to add most binops to | 2200 // TODO(olivf) We should investigate why adding stubs to the snapshot is so |
2250 // the snapshot instead of hand-picking them. | 2201 // expensive at runtime. When solved we should be able to add most binops to |
2251 // Generated list of commonly used stubs | 2202 // the snapshot instead of hand-picking them. |
2252 #define GENERATE(op, left_kind, right_kind, result_kind, mode) \ | 2203 // Generated list of commonly used stubs |
2253 do { \ | 2204 #define GENERATE(op, left_kind, right_kind, result_kind, mode) \ |
2254 State state(isolate, op, mode); \ | 2205 do { \ |
2255 state.left_kind_ = left_kind; \ | 2206 State state(isolate, op, mode); \ |
2256 state.fixed_right_arg_.has_value = false; \ | 2207 state.left_kind_ = left_kind; \ |
2257 state.right_kind_ = right_kind; \ | 2208 state.fixed_right_arg_.has_value = false; \ |
2258 state.result_kind_ = result_kind; \ | 2209 state.right_kind_ = right_kind; \ |
2259 Generate(isolate, state); \ | 2210 state.result_kind_ = result_kind; \ |
| 2211 Generate(isolate, state); \ |
2260 } while (false) | 2212 } while (false) |
2261 GENERATE(Token::ADD, INT32, INT32, INT32, NO_OVERWRITE); | 2213 GENERATE(Token::ADD, INT32, INT32, INT32, NO_OVERWRITE); |
2262 GENERATE(Token::ADD, INT32, INT32, INT32, OVERWRITE_LEFT); | 2214 GENERATE(Token::ADD, INT32, INT32, INT32, OVERWRITE_LEFT); |
2263 GENERATE(Token::ADD, INT32, INT32, NUMBER, NO_OVERWRITE); | 2215 GENERATE(Token::ADD, INT32, INT32, NUMBER, NO_OVERWRITE); |
2264 GENERATE(Token::ADD, INT32, INT32, NUMBER, OVERWRITE_LEFT); | 2216 GENERATE(Token::ADD, INT32, INT32, NUMBER, OVERWRITE_LEFT); |
2265 GENERATE(Token::ADD, INT32, NUMBER, NUMBER, NO_OVERWRITE); | 2217 GENERATE(Token::ADD, INT32, NUMBER, NUMBER, NO_OVERWRITE); |
2266 GENERATE(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_LEFT); | 2218 GENERATE(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_LEFT); |
2267 GENERATE(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT); | 2219 GENERATE(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT); |
2268 GENERATE(Token::ADD, INT32, SMI, INT32, NO_OVERWRITE); | 2220 GENERATE(Token::ADD, INT32, SMI, INT32, NO_OVERWRITE); |
2269 GENERATE(Token::ADD, INT32, SMI, INT32, OVERWRITE_LEFT); | 2221 GENERATE(Token::ADD, INT32, SMI, INT32, OVERWRITE_LEFT); |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2489 os << ":" << BinaryOpIC::State::KindToString(s.left_kind_) << "*"; | 2441 os << ":" << BinaryOpIC::State::KindToString(s.left_kind_) << "*"; |
2490 if (s.fixed_right_arg_.has_value) { | 2442 if (s.fixed_right_arg_.has_value) { |
2491 os << s.fixed_right_arg_.value; | 2443 os << s.fixed_right_arg_.value; |
2492 } else { | 2444 } else { |
2493 os << BinaryOpIC::State::KindToString(s.right_kind_); | 2445 os << BinaryOpIC::State::KindToString(s.right_kind_); |
2494 } | 2446 } |
2495 return os << "->" << BinaryOpIC::State::KindToString(s.result_kind_) << ")"; | 2447 return os << "->" << BinaryOpIC::State::KindToString(s.result_kind_) << ")"; |
2496 } | 2448 } |
2497 | 2449 |
2498 | 2450 |
2499 void BinaryOpIC::State::Update(Handle<Object> left, | 2451 void BinaryOpIC::State::Update(Handle<Object> left, Handle<Object> right, |
2500 Handle<Object> right, | |
2501 Handle<Object> result) { | 2452 Handle<Object> result) { |
2502 ExtraICState old_extra_ic_state = GetExtraICState(); | 2453 ExtraICState old_extra_ic_state = GetExtraICState(); |
2503 | 2454 |
2504 left_kind_ = UpdateKind(left, left_kind_); | 2455 left_kind_ = UpdateKind(left, left_kind_); |
2505 right_kind_ = UpdateKind(right, right_kind_); | 2456 right_kind_ = UpdateKind(right, right_kind_); |
2506 | 2457 |
2507 int32_t fixed_right_arg_value = 0; | 2458 int32_t fixed_right_arg_value = 0; |
2508 bool has_fixed_right_arg = | 2459 bool has_fixed_right_arg = |
2509 op_ == Token::MOD && | 2460 op_ == Token::MOD && right->ToInt32(&fixed_right_arg_value) && |
2510 right->ToInt32(&fixed_right_arg_value) && | 2461 fixed_right_arg_value > 0 && IsPowerOf2(fixed_right_arg_value) && |
2511 fixed_right_arg_value > 0 && | |
2512 IsPowerOf2(fixed_right_arg_value) && | |
2513 FixedRightArgValueField::is_valid(WhichPowerOf2(fixed_right_arg_value)) && | 2462 FixedRightArgValueField::is_valid(WhichPowerOf2(fixed_right_arg_value)) && |
2514 (left_kind_ == SMI || left_kind_ == INT32) && | 2463 (left_kind_ == SMI || left_kind_ == INT32) && |
2515 (result_kind_ == NONE || !fixed_right_arg_.has_value); | 2464 (result_kind_ == NONE || !fixed_right_arg_.has_value); |
2516 fixed_right_arg_ = Maybe<int32_t>(has_fixed_right_arg, | 2465 fixed_right_arg_ = Maybe<int32_t>(has_fixed_right_arg, fixed_right_arg_value); |
2517 fixed_right_arg_value); | |
2518 | 2466 |
2519 result_kind_ = UpdateKind(result, result_kind_); | 2467 result_kind_ = UpdateKind(result, result_kind_); |
2520 | 2468 |
2521 if (!Token::IsTruncatingBinaryOp(op_)) { | 2469 if (!Token::IsTruncatingBinaryOp(op_)) { |
2522 Kind input_kind = Max(left_kind_, right_kind_); | 2470 Kind input_kind = Max(left_kind_, right_kind_); |
2523 if (result_kind_ < input_kind && input_kind <= NUMBER) { | 2471 if (result_kind_ < input_kind && input_kind <= NUMBER) { |
2524 result_kind_ = input_kind; | 2472 result_kind_ = input_kind; |
2525 } | 2473 } |
2526 } | 2474 } |
2527 | 2475 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2571 new_kind = SMI; | 2519 new_kind = SMI; |
2572 } else if (object->IsHeapNumber()) { | 2520 } else if (object->IsHeapNumber()) { |
2573 double value = Handle<HeapNumber>::cast(object)->value(); | 2521 double value = Handle<HeapNumber>::cast(object)->value(); |
2574 new_kind = IsInt32Double(value) ? INT32 : NUMBER; | 2522 new_kind = IsInt32Double(value) ? INT32 : NUMBER; |
2575 } else if (object->IsString() && op() == Token::ADD) { | 2523 } else if (object->IsString() && op() == Token::ADD) { |
2576 new_kind = STRING; | 2524 new_kind = STRING; |
2577 } | 2525 } |
2578 if (new_kind == INT32 && SmiValuesAre32Bits()) { | 2526 if (new_kind == INT32 && SmiValuesAre32Bits()) { |
2579 new_kind = NUMBER; | 2527 new_kind = NUMBER; |
2580 } | 2528 } |
2581 if (kind != NONE && | 2529 if (kind != NONE && ((new_kind <= NUMBER && kind > NUMBER) || |
2582 ((new_kind <= NUMBER && kind > NUMBER) || | 2530 (new_kind > NUMBER && kind <= NUMBER))) { |
2583 (new_kind > NUMBER && kind <= NUMBER))) { | |
2584 new_kind = GENERIC; | 2531 new_kind = GENERIC; |
2585 } | 2532 } |
2586 return Max(kind, new_kind); | 2533 return Max(kind, new_kind); |
2587 } | 2534 } |
2588 | 2535 |
2589 | 2536 |
2590 // static | 2537 // static |
2591 const char* BinaryOpIC::State::KindToString(Kind kind) { | 2538 const char* BinaryOpIC::State::KindToString(Kind kind) { |
2592 switch (kind) { | 2539 switch (kind) { |
2593 case NONE: return "None"; | 2540 case NONE: |
2594 case SMI: return "Smi"; | 2541 return "None"; |
2595 case INT32: return "Int32"; | 2542 case SMI: |
2596 case NUMBER: return "Number"; | 2543 return "Smi"; |
2597 case STRING: return "String"; | 2544 case INT32: |
2598 case GENERIC: return "Generic"; | 2545 return "Int32"; |
| 2546 case NUMBER: |
| 2547 return "Number"; |
| 2548 case STRING: |
| 2549 return "String"; |
| 2550 case GENERIC: |
| 2551 return "Generic"; |
2599 } | 2552 } |
2600 UNREACHABLE(); | 2553 UNREACHABLE(); |
2601 return NULL; | 2554 return NULL; |
2602 } | 2555 } |
2603 | 2556 |
2604 | 2557 |
2605 // static | 2558 // static |
2606 Type* BinaryOpIC::State::KindToType(Kind kind, Zone* zone) { | 2559 Type* BinaryOpIC::State::KindToType(Kind kind, Zone* zone) { |
2607 switch (kind) { | 2560 switch (kind) { |
2608 case NONE: return Type::None(zone); | 2561 case NONE: |
2609 case SMI: return Type::SignedSmall(zone); | 2562 return Type::None(zone); |
2610 case INT32: return Type::Signed32(zone); | 2563 case SMI: |
2611 case NUMBER: return Type::Number(zone); | 2564 return Type::SignedSmall(zone); |
2612 case STRING: return Type::String(zone); | 2565 case INT32: |
2613 case GENERIC: return Type::Any(zone); | 2566 return Type::Signed32(zone); |
| 2567 case NUMBER: |
| 2568 return Type::Number(zone); |
| 2569 case STRING: |
| 2570 return Type::String(zone); |
| 2571 case GENERIC: |
| 2572 return Type::Any(zone); |
2614 } | 2573 } |
2615 UNREACHABLE(); | 2574 UNREACHABLE(); |
2616 return NULL; | 2575 return NULL; |
2617 } | 2576 } |
2618 | 2577 |
2619 | 2578 |
2620 MaybeHandle<Object> BinaryOpIC::Transition( | 2579 MaybeHandle<Object> BinaryOpIC::Transition( |
2621 Handle<AllocationSite> allocation_site, | 2580 Handle<AllocationSite> allocation_site, Handle<Object> left, |
2622 Handle<Object> left, | |
2623 Handle<Object> right) { | 2581 Handle<Object> right) { |
2624 State state(isolate(), target()->extra_ic_state()); | 2582 State state(isolate(), target()->extra_ic_state()); |
2625 | 2583 |
2626 // Compute the actual result using the builtin for the binary operation. | 2584 // Compute the actual result using the builtin for the binary operation. |
2627 Object* builtin = isolate()->js_builtins_object()->javascript_builtin( | 2585 Object* builtin = isolate()->js_builtins_object()->javascript_builtin( |
2628 TokenToJSBuiltin(state.op())); | 2586 TokenToJSBuiltin(state.op())); |
2629 Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate()); | 2587 Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate()); |
2630 Handle<Object> result; | 2588 Handle<Object> result; |
2631 ASSIGN_RETURN_ON_EXCEPTION( | 2589 ASSIGN_RETURN_ON_EXCEPTION( |
2632 isolate(), | 2590 isolate(), result, Execution::Call(isolate(), function, left, 1, &right), |
2633 result, | |
2634 Execution::Call(isolate(), function, left, 1, &right), | |
2635 Object); | 2591 Object); |
2636 | 2592 |
2637 // Execution::Call can execute arbitrary JavaScript, hence potentially | 2593 // Execution::Call can execute arbitrary JavaScript, hence potentially |
2638 // update the state of this very IC, so we must update the stored state. | 2594 // update the state of this very IC, so we must update the stored state. |
2639 UpdateTarget(); | 2595 UpdateTarget(); |
2640 // Compute the new state. | 2596 // Compute the new state. |
2641 State old_state(isolate(), target()->extra_ic_state()); | 2597 State old_state(isolate(), target()->extra_ic_state()); |
2642 state.Update(left, right, result); | 2598 state.Update(left, right, result); |
2643 | 2599 |
2644 // Check if we have a string operation here. | 2600 // Check if we have a string operation here. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2689 | 2645 |
2690 RUNTIME_FUNCTION(BinaryOpIC_Miss) { | 2646 RUNTIME_FUNCTION(BinaryOpIC_Miss) { |
2691 TimerEventScope<TimerEventIcMiss> timer(isolate); | 2647 TimerEventScope<TimerEventIcMiss> timer(isolate); |
2692 HandleScope scope(isolate); | 2648 HandleScope scope(isolate); |
2693 DCHECK_EQ(2, args.length()); | 2649 DCHECK_EQ(2, args.length()); |
2694 Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft); | 2650 Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft); |
2695 Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight); | 2651 Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight); |
2696 BinaryOpIC ic(isolate); | 2652 BinaryOpIC ic(isolate); |
2697 Handle<Object> result; | 2653 Handle<Object> result; |
2698 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 2654 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
2699 isolate, | 2655 isolate, result, |
2700 result, | |
2701 ic.Transition(Handle<AllocationSite>::null(), left, right)); | 2656 ic.Transition(Handle<AllocationSite>::null(), left, right)); |
2702 return *result; | 2657 return *result; |
2703 } | 2658 } |
2704 | 2659 |
2705 | 2660 |
2706 RUNTIME_FUNCTION(BinaryOpIC_MissWithAllocationSite) { | 2661 RUNTIME_FUNCTION(BinaryOpIC_MissWithAllocationSite) { |
2707 TimerEventScope<TimerEventIcMiss> timer(isolate); | 2662 TimerEventScope<TimerEventIcMiss> timer(isolate); |
2708 HandleScope scope(isolate); | 2663 HandleScope scope(isolate); |
2709 DCHECK_EQ(3, args.length()); | 2664 DCHECK_EQ(3, args.length()); |
2710 Handle<AllocationSite> allocation_site = args.at<AllocationSite>( | 2665 Handle<AllocationSite> allocation_site = |
2711 BinaryOpWithAllocationSiteStub::kAllocationSite); | 2666 args.at<AllocationSite>(BinaryOpWithAllocationSiteStub::kAllocationSite); |
2712 Handle<Object> left = args.at<Object>( | 2667 Handle<Object> left = args.at<Object>(BinaryOpWithAllocationSiteStub::kLeft); |
2713 BinaryOpWithAllocationSiteStub::kLeft); | 2668 Handle<Object> right = |
2714 Handle<Object> right = args.at<Object>( | 2669 args.at<Object>(BinaryOpWithAllocationSiteStub::kRight); |
2715 BinaryOpWithAllocationSiteStub::kRight); | |
2716 BinaryOpIC ic(isolate); | 2670 BinaryOpIC ic(isolate); |
2717 Handle<Object> result; | 2671 Handle<Object> result; |
2718 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 2672 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
2719 isolate, | 2673 isolate, result, ic.Transition(allocation_site, left, right)); |
2720 result, | |
2721 ic.Transition(allocation_site, left, right)); | |
2722 return *result; | 2674 return *result; |
2723 } | 2675 } |
2724 | 2676 |
2725 | 2677 |
2726 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { | 2678 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { |
2727 ICCompareStub stub(isolate, op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2679 ICCompareStub stub(isolate, op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
2728 Code* code = NULL; | 2680 Code* code = NULL; |
2729 CHECK(stub.FindCodeInCache(&code)); | 2681 CHECK(stub.FindCodeInCache(&code)); |
2730 return code; | 2682 return code; |
2731 } | 2683 } |
2732 | 2684 |
2733 | 2685 |
2734 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { | 2686 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { |
2735 ICCompareStub stub(isolate, op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2687 ICCompareStub stub(isolate, op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
2736 return stub.GetCode(); | 2688 return stub.GetCode(); |
2737 } | 2689 } |
2738 | 2690 |
2739 | 2691 |
2740 const char* CompareIC::GetStateName(State state) { | 2692 const char* CompareIC::GetStateName(State state) { |
2741 switch (state) { | 2693 switch (state) { |
2742 case UNINITIALIZED: return "UNINITIALIZED"; | 2694 case UNINITIALIZED: |
2743 case SMI: return "SMI"; | 2695 return "UNINITIALIZED"; |
2744 case NUMBER: return "NUMBER"; | 2696 case SMI: |
2745 case INTERNALIZED_STRING: return "INTERNALIZED_STRING"; | 2697 return "SMI"; |
2746 case STRING: return "STRING"; | 2698 case NUMBER: |
2747 case UNIQUE_NAME: return "UNIQUE_NAME"; | 2699 return "NUMBER"; |
2748 case OBJECT: return "OBJECT"; | 2700 case INTERNALIZED_STRING: |
2749 case KNOWN_OBJECT: return "KNOWN_OBJECT"; | 2701 return "INTERNALIZED_STRING"; |
2750 case GENERIC: return "GENERIC"; | 2702 case STRING: |
| 2703 return "STRING"; |
| 2704 case UNIQUE_NAME: |
| 2705 return "UNIQUE_NAME"; |
| 2706 case OBJECT: |
| 2707 return "OBJECT"; |
| 2708 case KNOWN_OBJECT: |
| 2709 return "KNOWN_OBJECT"; |
| 2710 case GENERIC: |
| 2711 return "GENERIC"; |
2751 } | 2712 } |
2752 UNREACHABLE(); | 2713 UNREACHABLE(); |
2753 return NULL; | 2714 return NULL; |
2754 } | 2715 } |
2755 | 2716 |
2756 | 2717 |
2757 Type* CompareIC::StateToType( | 2718 Type* CompareIC::StateToType(Zone* zone, CompareIC::State state, |
2758 Zone* zone, | 2719 Handle<Map> map) { |
2759 CompareIC::State state, | |
2760 Handle<Map> map) { | |
2761 switch (state) { | 2720 switch (state) { |
2762 case CompareIC::UNINITIALIZED: return Type::None(zone); | 2721 case CompareIC::UNINITIALIZED: |
2763 case CompareIC::SMI: return Type::SignedSmall(zone); | 2722 return Type::None(zone); |
2764 case CompareIC::NUMBER: return Type::Number(zone); | 2723 case CompareIC::SMI: |
2765 case CompareIC::STRING: return Type::String(zone); | 2724 return Type::SignedSmall(zone); |
2766 case CompareIC::INTERNALIZED_STRING: return Type::InternalizedString(zone); | 2725 case CompareIC::NUMBER: |
2767 case CompareIC::UNIQUE_NAME: return Type::UniqueName(zone); | 2726 return Type::Number(zone); |
2768 case CompareIC::OBJECT: return Type::Receiver(zone); | 2727 case CompareIC::STRING: |
| 2728 return Type::String(zone); |
| 2729 case CompareIC::INTERNALIZED_STRING: |
| 2730 return Type::InternalizedString(zone); |
| 2731 case CompareIC::UNIQUE_NAME: |
| 2732 return Type::UniqueName(zone); |
| 2733 case CompareIC::OBJECT: |
| 2734 return Type::Receiver(zone); |
2769 case CompareIC::KNOWN_OBJECT: | 2735 case CompareIC::KNOWN_OBJECT: |
2770 return map.is_null() ? Type::Receiver(zone) : Type::Class(map, zone); | 2736 return map.is_null() ? Type::Receiver(zone) : Type::Class(map, zone); |
2771 case CompareIC::GENERIC: return Type::Any(zone); | 2737 case CompareIC::GENERIC: |
| 2738 return Type::Any(zone); |
2772 } | 2739 } |
2773 UNREACHABLE(); | 2740 UNREACHABLE(); |
2774 return NULL; | 2741 return NULL; |
2775 } | 2742 } |
2776 | 2743 |
2777 | 2744 |
2778 void CompareIC::StubInfoToType(uint32_t stub_key, Type** left_type, | 2745 void CompareIC::StubInfoToType(uint32_t stub_key, Type** left_type, |
2779 Type** right_type, Type** overall_type, | 2746 Type** right_type, Type** overall_type, |
2780 Handle<Map> map, Zone* zone) { | 2747 Handle<Map> map, Zone* zone) { |
2781 State left_state, right_state, handler_state; | 2748 State left_state, right_state, handler_state; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2822 case GENERIC: | 2789 case GENERIC: |
2823 break; | 2790 break; |
2824 case KNOWN_OBJECT: | 2791 case KNOWN_OBJECT: |
2825 UNREACHABLE(); | 2792 UNREACHABLE(); |
2826 break; | 2793 break; |
2827 } | 2794 } |
2828 return GENERIC; | 2795 return GENERIC; |
2829 } | 2796 } |
2830 | 2797 |
2831 | 2798 |
2832 CompareIC::State CompareIC::TargetState(State old_state, | 2799 CompareIC::State CompareIC::TargetState(State old_state, State old_left, |
2833 State old_left, | |
2834 State old_right, | 2800 State old_right, |
2835 bool has_inlined_smi_code, | 2801 bool has_inlined_smi_code, |
2836 Handle<Object> x, | 2802 Handle<Object> x, Handle<Object> y) { |
2837 Handle<Object> y) { | |
2838 switch (old_state) { | 2803 switch (old_state) { |
2839 case UNINITIALIZED: | 2804 case UNINITIALIZED: |
2840 if (x->IsSmi() && y->IsSmi()) return SMI; | 2805 if (x->IsSmi() && y->IsSmi()) return SMI; |
2841 if (x->IsNumber() && y->IsNumber()) return NUMBER; | 2806 if (x->IsNumber() && y->IsNumber()) return NUMBER; |
2842 if (Token::IsOrderedRelationalCompareOp(op_)) { | 2807 if (Token::IsOrderedRelationalCompareOp(op_)) { |
2843 // Ordered comparisons treat undefined as NaN, so the | 2808 // Ordered comparisons treat undefined as NaN, so the |
2844 // NUMBER stub will do the right thing. | 2809 // NUMBER stub will do the right thing. |
2845 if ((x->IsNumber() && y->IsUndefined()) || | 2810 if ((x->IsNumber() && y->IsUndefined()) || |
2846 (y->IsNumber() && x->IsUndefined())) { | 2811 (y->IsNumber() && x->IsUndefined())) { |
2847 return NUMBER; | 2812 return NUMBER; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2906 if (state == KNOWN_OBJECT) { | 2871 if (state == KNOWN_OBJECT) { |
2907 stub.set_known_map( | 2872 stub.set_known_map( |
2908 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate())); | 2873 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate())); |
2909 } | 2874 } |
2910 Handle<Code> new_target = stub.GetCode(); | 2875 Handle<Code> new_target = stub.GetCode(); |
2911 set_target(*new_target); | 2876 set_target(*new_target); |
2912 | 2877 |
2913 if (FLAG_trace_ic) { | 2878 if (FLAG_trace_ic) { |
2914 PrintF("[CompareIC in "); | 2879 PrintF("[CompareIC in "); |
2915 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); | 2880 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
2916 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n", | 2881 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n", GetStateName(previous_left), |
2917 GetStateName(previous_left), | 2882 GetStateName(previous_right), GetStateName(previous_state), |
2918 GetStateName(previous_right), | 2883 GetStateName(new_left), GetStateName(new_right), GetStateName(state), |
2919 GetStateName(previous_state), | 2884 Token::Name(op_), static_cast<void*>(*stub.GetCode())); |
2920 GetStateName(new_left), | |
2921 GetStateName(new_right), | |
2922 GetStateName(state), | |
2923 Token::Name(op_), | |
2924 static_cast<void*>(*stub.GetCode())); | |
2925 } | 2885 } |
2926 | 2886 |
2927 // Activate inlined smi code. | 2887 // Activate inlined smi code. |
2928 if (previous_state == UNINITIALIZED) { | 2888 if (previous_state == UNINITIALIZED) { |
2929 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); | 2889 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
2930 } | 2890 } |
2931 | 2891 |
2932 return *new_target; | 2892 return *new_target; |
2933 } | 2893 } |
2934 | 2894 |
2935 | 2895 |
2936 // Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc. | 2896 // Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc. |
2937 RUNTIME_FUNCTION(CompareIC_Miss) { | 2897 RUNTIME_FUNCTION(CompareIC_Miss) { |
2938 TimerEventScope<TimerEventIcMiss> timer(isolate); | 2898 TimerEventScope<TimerEventIcMiss> timer(isolate); |
2939 HandleScope scope(isolate); | 2899 HandleScope scope(isolate); |
2940 DCHECK(args.length() == 3); | 2900 DCHECK(args.length() == 3); |
2941 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2))); | 2901 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2))); |
2942 return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); | 2902 return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); |
2943 } | 2903 } |
2944 | 2904 |
2945 | 2905 |
2946 void CompareNilIC::Clear(Address address, | 2906 void CompareNilIC::Clear(Address address, Code* target, |
2947 Code* target, | |
2948 ConstantPoolArray* constant_pool) { | 2907 ConstantPoolArray* constant_pool) { |
2949 if (IsCleared(target)) return; | 2908 if (IsCleared(target)) return; |
2950 ExtraICState state = target->extra_ic_state(); | 2909 ExtraICState state = target->extra_ic_state(); |
2951 | 2910 |
2952 CompareNilICStub stub(target->GetIsolate(), | 2911 CompareNilICStub stub(target->GetIsolate(), state, |
2953 state, | |
2954 HydrogenCodeStub::UNINITIALIZED); | 2912 HydrogenCodeStub::UNINITIALIZED); |
2955 stub.ClearState(); | 2913 stub.ClearState(); |
2956 | 2914 |
2957 Code* code = NULL; | 2915 Code* code = NULL; |
2958 CHECK(stub.FindCodeInCache(&code)); | 2916 CHECK(stub.FindCodeInCache(&code)); |
2959 | 2917 |
2960 SetTargetAtAddress(address, code, constant_pool); | 2918 SetTargetAtAddress(address, code, constant_pool); |
2961 } | 2919 } |
2962 | 2920 |
2963 | 2921 |
2964 Handle<Object> CompareNilIC::DoCompareNilSlow(Isolate* isolate, | 2922 Handle<Object> CompareNilIC::DoCompareNilSlow(Isolate* isolate, NilValue nil, |
2965 NilValue nil, | |
2966 Handle<Object> object) { | 2923 Handle<Object> object) { |
2967 if (object->IsNull() || object->IsUndefined()) { | 2924 if (object->IsNull() || object->IsUndefined()) { |
2968 return handle(Smi::FromInt(true), isolate); | 2925 return handle(Smi::FromInt(true), isolate); |
2969 } | 2926 } |
2970 return handle(Smi::FromInt(object->IsUndetectableObject()), isolate); | 2927 return handle(Smi::FromInt(object->IsUndetectableObject()), isolate); |
2971 } | 2928 } |
2972 | 2929 |
2973 | 2930 |
2974 Handle<Object> CompareNilIC::CompareNil(Handle<Object> object) { | 2931 Handle<Object> CompareNilIC::CompareNil(Handle<Object> object) { |
2975 ExtraICState extra_ic_state = target()->extra_ic_state(); | 2932 ExtraICState extra_ic_state = target()->extra_ic_state(); |
2976 | 2933 |
2977 CompareNilICStub stub(isolate(), extra_ic_state); | 2934 CompareNilICStub stub(isolate(), extra_ic_state); |
2978 | 2935 |
2979 // Extract the current supported types from the patched IC and calculate what | 2936 // Extract the current supported types from the patched IC and calculate what |
2980 // types must be supported as a result of the miss. | 2937 // types must be supported as a result of the miss. |
2981 bool already_monomorphic = stub.IsMonomorphic(); | 2938 bool already_monomorphic = stub.IsMonomorphic(); |
2982 | 2939 |
2983 stub.UpdateStatus(object); | 2940 stub.UpdateStatus(object); |
2984 | 2941 |
2985 NilValue nil = stub.GetNilValue(); | 2942 NilValue nil = stub.GetNilValue(); |
2986 | 2943 |
2987 // Find or create the specialized stub to support the new set of types. | 2944 // Find or create the specialized stub to support the new set of types. |
2988 Handle<Code> code; | 2945 Handle<Code> code; |
2989 if (stub.IsMonomorphic()) { | 2946 if (stub.IsMonomorphic()) { |
2990 Handle<Map> monomorphic_map(already_monomorphic && FirstTargetMap() != NULL | 2947 Handle<Map> monomorphic_map(already_monomorphic && FirstTargetMap() != NULL |
2991 ? FirstTargetMap() | 2948 ? FirstTargetMap() |
2992 : HeapObject::cast(*object)->map()); | 2949 : HeapObject::cast(*object)->map()); |
2993 code = PropertyICCompiler::ComputeCompareNil(monomorphic_map, &stub); | 2950 code = PropertyICCompiler::ComputeCompareNil(monomorphic_map, &stub); |
2994 } else { | 2951 } else { |
2995 code = stub.GetCode(); | 2952 code = stub.GetCode(); |
2996 } | 2953 } |
2997 set_target(*code); | 2954 set_target(*code); |
2998 return DoCompareNilSlow(isolate(), nil, object); | 2955 return DoCompareNilSlow(isolate(), nil, object); |
2999 } | 2956 } |
3000 | 2957 |
3001 | 2958 |
3002 RUNTIME_FUNCTION(CompareNilIC_Miss) { | 2959 RUNTIME_FUNCTION(CompareNilIC_Miss) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3068 RUNTIME_FUNCTION(ToBooleanIC_Miss) { | 3025 RUNTIME_FUNCTION(ToBooleanIC_Miss) { |
3069 TimerEventScope<TimerEventIcMiss> timer(isolate); | 3026 TimerEventScope<TimerEventIcMiss> timer(isolate); |
3070 DCHECK(args.length() == 1); | 3027 DCHECK(args.length() == 1); |
3071 HandleScope scope(isolate); | 3028 HandleScope scope(isolate); |
3072 Handle<Object> object = args.at<Object>(0); | 3029 Handle<Object> object = args.at<Object>(0); |
3073 ToBooleanIC ic(isolate); | 3030 ToBooleanIC ic(isolate); |
3074 return *ic.ToBoolean(object); | 3031 return *ic.ToBoolean(object); |
3075 } | 3032 } |
3076 | 3033 |
3077 | 3034 |
| 3035 RUNTIME_FUNCTION(StoreCallbackProperty) { |
| 3036 Handle<JSObject> receiver = args.at<JSObject>(0); |
| 3037 Handle<JSObject> holder = args.at<JSObject>(1); |
| 3038 Handle<ExecutableAccessorInfo> callback = args.at<ExecutableAccessorInfo>(2); |
| 3039 Handle<Name> name = args.at<Name>(3); |
| 3040 Handle<Object> value = args.at<Object>(4); |
| 3041 HandleScope scope(isolate); |
| 3042 |
| 3043 DCHECK(callback->IsCompatibleReceiver(*receiver)); |
| 3044 |
| 3045 Address setter_address = v8::ToCData<Address>(callback->setter()); |
| 3046 v8::AccessorNameSetterCallback fun = |
| 3047 FUNCTION_CAST<v8::AccessorNameSetterCallback>(setter_address); |
| 3048 DCHECK(fun != NULL); |
| 3049 |
| 3050 LOG(isolate, ApiNamedPropertyAccess("store", *receiver, *name)); |
| 3051 PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver, |
| 3052 *holder); |
| 3053 custom_args.Call(fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value)); |
| 3054 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); |
| 3055 return *value; |
| 3056 } |
| 3057 |
| 3058 |
| 3059 /** |
| 3060 * Attempts to load a property with an interceptor (which must be present), |
| 3061 * but doesn't search the prototype chain. |
| 3062 * |
| 3063 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't |
| 3064 * provide any value for the given name. |
| 3065 */ |
| 3066 RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly) { |
| 3067 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength); |
| 3068 Handle<Name> name_handle = |
| 3069 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex); |
| 3070 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>( |
| 3071 NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex); |
| 3072 |
| 3073 // TODO(rossberg): Support symbols in the API. |
| 3074 if (name_handle->IsSymbol()) |
| 3075 return isolate->heap()->no_interceptor_result_sentinel(); |
| 3076 Handle<String> name = Handle<String>::cast(name_handle); |
| 3077 |
| 3078 Address getter_address = v8::ToCData<Address>(interceptor_info->getter()); |
| 3079 v8::NamedPropertyGetterCallback getter = |
| 3080 FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address); |
| 3081 DCHECK(getter != NULL); |
| 3082 |
| 3083 Handle<JSObject> receiver = |
| 3084 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex); |
| 3085 Handle<JSObject> holder = |
| 3086 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex); |
| 3087 PropertyCallbackArguments callback_args(isolate, interceptor_info->data(), |
| 3088 *receiver, *holder); |
| 3089 { |
| 3090 // Use the interceptor getter. |
| 3091 HandleScope scope(isolate); |
| 3092 v8::Handle<v8::Value> r = |
| 3093 callback_args.Call(getter, v8::Utils::ToLocal(name)); |
| 3094 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); |
| 3095 if (!r.IsEmpty()) { |
| 3096 Handle<Object> result = v8::Utils::OpenHandle(*r); |
| 3097 result->VerifyApiCallResultType(); |
| 3098 return *v8::Utils::OpenHandle(*r); |
| 3099 } |
| 3100 } |
| 3101 |
| 3102 return isolate->heap()->no_interceptor_result_sentinel(); |
| 3103 } |
| 3104 |
| 3105 |
| 3106 static Object* ThrowReferenceError(Isolate* isolate, Name* name) { |
| 3107 // If the load is non-contextual, just return the undefined result. |
| 3108 // Note that both keyed and non-keyed loads may end up here. |
| 3109 HandleScope scope(isolate); |
| 3110 LoadIC ic(IC::NO_EXTRA_FRAME, isolate); |
| 3111 if (ic.contextual_mode() != CONTEXTUAL) { |
| 3112 return isolate->heap()->undefined_value(); |
| 3113 } |
| 3114 |
| 3115 // Throw a reference error. |
| 3116 Handle<Name> name_handle(name); |
| 3117 Handle<Object> error = isolate->factory()->NewReferenceError( |
| 3118 "not_defined", HandleVector(&name_handle, 1)); |
| 3119 return isolate->Throw(*error); |
| 3120 } |
| 3121 |
| 3122 |
| 3123 /** |
| 3124 * Loads a property with an interceptor performing post interceptor |
| 3125 * lookup if interceptor failed. |
| 3126 */ |
| 3127 RUNTIME_FUNCTION(LoadPropertyWithInterceptor) { |
| 3128 HandleScope scope(isolate); |
| 3129 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength); |
| 3130 Handle<Name> name = |
| 3131 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex); |
| 3132 Handle<JSObject> receiver = |
| 3133 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex); |
| 3134 Handle<JSObject> holder = |
| 3135 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex); |
| 3136 |
| 3137 Handle<Object> result; |
| 3138 LookupIterator it(receiver, name, holder); |
| 3139 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |
| 3140 JSObject::GetProperty(&it)); |
| 3141 |
| 3142 if (it.IsFound()) return *result; |
| 3143 |
| 3144 return ThrowReferenceError(isolate, Name::cast(args[0])); |
| 3145 } |
| 3146 |
| 3147 |
| 3148 RUNTIME_FUNCTION(StorePropertyWithInterceptor) { |
| 3149 HandleScope scope(isolate); |
| 3150 DCHECK(args.length() == 3); |
| 3151 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
| 3152 Handle<JSObject> receiver = args.at<JSObject>(0); |
| 3153 Handle<Name> name = args.at<Name>(1); |
| 3154 Handle<Object> value = args.at<Object>(2); |
| 3155 #ifdef DEBUG |
| 3156 PrototypeIterator iter(isolate, receiver, |
| 3157 PrototypeIterator::START_AT_RECEIVER); |
| 3158 bool found = false; |
| 3159 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { |
| 3160 Handle<Object> current = PrototypeIterator::GetCurrent(iter); |
| 3161 if (current->IsJSObject() && |
| 3162 Handle<JSObject>::cast(current)->HasNamedInterceptor()) { |
| 3163 found = true; |
| 3164 break; |
| 3165 } |
| 3166 } |
| 3167 DCHECK(found); |
| 3168 #endif |
| 3169 Handle<Object> result; |
| 3170 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 3171 isolate, result, |
| 3172 JSObject::SetProperty(receiver, name, value, ic.strict_mode())); |
| 3173 return *result; |
| 3174 } |
| 3175 |
| 3176 |
| 3177 RUNTIME_FUNCTION(LoadElementWithInterceptor) { |
| 3178 HandleScope scope(isolate); |
| 3179 Handle<JSObject> receiver = args.at<JSObject>(0); |
| 3180 DCHECK(args.smi_at(1) >= 0); |
| 3181 uint32_t index = args.smi_at(1); |
| 3182 Handle<Object> result; |
| 3183 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 3184 isolate, result, |
| 3185 JSObject::GetElementWithInterceptor(receiver, receiver, index)); |
| 3186 return *result; |
| 3187 } |
| 3188 |
| 3189 |
3078 static const Address IC_utilities[] = { | 3190 static const Address IC_utilities[] = { |
3079 #define ADDR(name) FUNCTION_ADDR(name), | 3191 #define ADDR(name) FUNCTION_ADDR(name), |
3080 IC_UTIL_LIST(ADDR) | 3192 IC_UTIL_LIST(ADDR) NULL |
3081 NULL | |
3082 #undef ADDR | 3193 #undef ADDR |
3083 }; | 3194 }; |
3084 | 3195 |
3085 | 3196 |
3086 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 3197 Address IC::AddressFromUtilityId(IC::UtilityId id) { return IC_utilities[id]; } |
3087 return IC_utilities[id]; | |
3088 } | 3198 } |
3089 | 3199 } // namespace v8::internal |
3090 | |
3091 } } // namespace v8::internal | |
OLD | NEW |