| 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 |