OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 3277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3288 | 3288 |
3289 Handle<JSFunction> f = | 3289 Handle<JSFunction> f = |
3290 v8::Utils::OpenHandle( | 3290 v8::Utils::OpenHandle( |
3291 *v8::Handle<v8::Function>::Cast( | 3291 *v8::Handle<v8::Function>::Cast( |
3292 CcTest::global()->Get(v8_str("f")))); | 3292 CcTest::global()->Get(v8_str("f")))); |
3293 | 3293 |
3294 Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector()); | 3294 Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector()); |
3295 | 3295 |
3296 int expected_slots = 2; | 3296 int expected_slots = 2; |
3297 CHECK_EQ(expected_slots, feedback_vector->ICSlots()); | 3297 CHECK_EQ(expected_slots, feedback_vector->ICSlots()); |
3298 for (int i = 0; i < expected_slots; i++) { | 3298 int slot1 = 0; |
3299 CHECK(feedback_vector->Get(FeedbackVectorICSlot(i))->IsJSFunction()); | 3299 int slot2 = 1; |
3300 } | 3300 CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot1))->IsJSFunction()); |
3301 CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot2))->IsJSFunction()); | |
3301 | 3302 |
3302 SimulateIncrementalMarking(CcTest::heap()); | 3303 SimulateIncrementalMarking(CcTest::heap()); |
3303 CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); | 3304 CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); |
3304 | 3305 |
3305 CHECK_EQ(expected_slots, feedback_vector->ICSlots()); | 3306 CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(slot1)), |
3306 for (int i = 0; i < expected_slots; i++) { | 3307 *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate())); |
3307 CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(i)), | 3308 CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(slot2)), |
3308 *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate())); | 3309 *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate())); |
3309 } | |
3310 } | 3310 } |
3311 | 3311 |
3312 | 3312 |
3313 static Code* FindFirstIC(Code* code, Code::Kind kind) { | 3313 static Code* FindFirstIC(Code* code, Code::Kind kind) { |
3314 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | | 3314 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | |
3315 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) | | 3315 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) | |
3316 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID); | 3316 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID); |
3317 for (RelocIterator it(code, mask); !it.done(); it.next()) { | 3317 for (RelocIterator it(code, mask); !it.done(); it.next()) { |
3318 RelocInfo* info = it.rinfo(); | 3318 RelocInfo* info = it.rinfo(); |
3319 Code* target = Code::GetCodeFromTargetAddress(info->target_address()); | 3319 Code* target = Code::GetCodeFromTargetAddress(info->target_address()); |
3320 if (target->is_inline_cache_stub() && target->kind() == kind) { | 3320 if (target->is_inline_cache_stub() && target->kind() == kind) { |
3321 return target; | 3321 return target; |
3322 } | 3322 } |
3323 } | 3323 } |
3324 return NULL; | 3324 return NULL; |
3325 } | 3325 } |
3326 | 3326 |
3327 | 3327 |
3328 static void CheckVectorIC(Handle<JSFunction> f, int ic_slot_index, | |
3329 InlineCacheState desired_state) { | |
3330 Handle<TypeFeedbackVector> vector = | |
3331 Handle<TypeFeedbackVector>(f->shared()->feedback_vector()); | |
3332 FeedbackVectorICSlot slot(ic_slot_index); | |
3333 LoadICNexus nexus(vector, slot); | |
3334 CHECK(nexus.StateFromFeedback() == MONOMORPHIC); | |
Jakob Kummerow
2014/11/26 15:14:15
uhm... s/MONOMORPHIC/desired_state/ maybe?
mvstanton
2014/11/27 13:09:26
Yes. Oh brother.
| |
3335 } | |
3336 | |
3337 | |
3338 static void CheckVectorICCleared(Handle<JSFunction> f, int ic_slot_index) { | |
3339 Handle<TypeFeedbackVector> vector = | |
3340 Handle<TypeFeedbackVector>(f->shared()->feedback_vector()); | |
3341 FeedbackVectorICSlot slot(ic_slot_index); | |
3342 LoadICNexus nexus(vector, slot); | |
3343 CHECK(IC::IsCleared(&nexus)); | |
3344 } | |
3345 | |
3346 | |
3328 TEST(IncrementalMarkingPreservesMonomorphicIC) { | 3347 TEST(IncrementalMarkingPreservesMonomorphicIC) { |
3329 if (i::FLAG_always_opt) return; | 3348 if (i::FLAG_always_opt) return; |
3330 CcTest::InitializeVM(); | 3349 CcTest::InitializeVM(); |
3331 v8::HandleScope scope(CcTest::isolate()); | 3350 v8::HandleScope scope(CcTest::isolate()); |
3332 | 3351 |
3333 // Prepare function f that contains a monomorphic IC for object | 3352 // Prepare function f that contains a monomorphic IC for object |
3334 // originating from the same native context. | 3353 // originating from the same native context. |
3335 CompileRun("function fun() { this.x = 1; }; var obj = new fun();" | 3354 CompileRun("function fun() { this.x = 1; }; var obj = new fun();" |
3336 "function f(o) { return o.x; } f(obj); f(obj);"); | 3355 "function f(o) { return o.x; } f(obj); f(obj);"); |
3337 Handle<JSFunction> f = | 3356 Handle<JSFunction> f = |
3338 v8::Utils::OpenHandle( | 3357 v8::Utils::OpenHandle( |
3339 *v8::Handle<v8::Function>::Cast( | 3358 *v8::Handle<v8::Function>::Cast( |
3340 CcTest::global()->Get(v8_str("f")))); | 3359 CcTest::global()->Get(v8_str("f")))); |
3341 | 3360 |
3342 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); | 3361 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); |
3343 CHECK(ic_before->ic_state() == MONOMORPHIC); | 3362 if (FLAG_vector_ics) { |
3363 CheckVectorIC(f, 0, MONOMORPHIC); | |
3364 CHECK(ic_before->ic_state() == DEFAULT); | |
3365 } else { | |
3366 CHECK(ic_before->ic_state() == MONOMORPHIC); | |
3367 } | |
3344 | 3368 |
3345 SimulateIncrementalMarking(CcTest::heap()); | 3369 SimulateIncrementalMarking(CcTest::heap()); |
3346 CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); | 3370 CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); |
3347 | 3371 |
3348 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); | 3372 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); |
3349 CHECK(ic_after->ic_state() == MONOMORPHIC); | 3373 if (FLAG_vector_ics) { |
3374 CheckVectorIC(f, 0, MONOMORPHIC); | |
3375 CHECK(ic_after->ic_state() == DEFAULT); | |
3376 } else { | |
3377 CHECK(ic_after->ic_state() == MONOMORPHIC); | |
3378 } | |
3350 } | 3379 } |
3351 | 3380 |
3352 | 3381 |
3353 TEST(IncrementalMarkingClearsMonomorphicIC) { | 3382 TEST(IncrementalMarkingClearsMonomorphicIC) { |
3354 if (i::FLAG_always_opt) return; | 3383 if (i::FLAG_always_opt) return; |
3355 CcTest::InitializeVM(); | 3384 CcTest::InitializeVM(); |
3356 v8::HandleScope scope(CcTest::isolate()); | 3385 v8::HandleScope scope(CcTest::isolate()); |
3357 v8::Local<v8::Value> obj1; | 3386 v8::Local<v8::Value> obj1; |
3358 | 3387 |
3359 { | 3388 { |
3360 LocalContext env; | 3389 LocalContext env; |
3361 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"); | 3390 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"); |
3362 obj1 = env->Global()->Get(v8_str("obj")); | 3391 obj1 = env->Global()->Get(v8_str("obj")); |
3363 } | 3392 } |
3364 | 3393 |
3365 // Prepare function f that contains a monomorphic IC for object | 3394 // Prepare function f that contains a monomorphic IC for object |
3366 // originating from a different native context. | 3395 // originating from a different native context. |
3367 CcTest::global()->Set(v8_str("obj1"), obj1); | 3396 CcTest::global()->Set(v8_str("obj1"), obj1); |
3368 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);"); | 3397 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);"); |
3369 Handle<JSFunction> f = | 3398 Handle<JSFunction> f = |
3370 v8::Utils::OpenHandle( | 3399 v8::Utils::OpenHandle( |
3371 *v8::Handle<v8::Function>::Cast( | 3400 *v8::Handle<v8::Function>::Cast( |
3372 CcTest::global()->Get(v8_str("f")))); | 3401 CcTest::global()->Get(v8_str("f")))); |
3373 | 3402 |
3374 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); | 3403 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); |
3375 CHECK(ic_before->ic_state() == MONOMORPHIC); | 3404 if (FLAG_vector_ics) { |
3405 CheckVectorIC(f, 0, MONOMORPHIC); | |
3406 CHECK(ic_before->ic_state() == DEFAULT); | |
3407 } else { | |
3408 CHECK(ic_before->ic_state() == MONOMORPHIC); | |
3409 } | |
3376 | 3410 |
3377 // Fire context dispose notification. | 3411 // Fire context dispose notification. |
3378 CcTest::isolate()->ContextDisposedNotification(); | 3412 CcTest::isolate()->ContextDisposedNotification(); |
3379 SimulateIncrementalMarking(CcTest::heap()); | 3413 SimulateIncrementalMarking(CcTest::heap()); |
3380 CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); | 3414 CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); |
3381 | 3415 |
3382 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); | 3416 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); |
3383 CHECK(IC::IsCleared(ic_after)); | 3417 if (FLAG_vector_ics) { |
3418 CheckVectorICCleared(f, 0); | |
3419 CHECK(ic_after->ic_state() == DEFAULT); | |
3420 } else { | |
3421 CHECK(IC::IsCleared(ic_after)); | |
3422 } | |
3384 } | 3423 } |
3385 | 3424 |
3386 | 3425 |
3387 TEST(IncrementalMarkingClearsPolymorphicIC) { | 3426 TEST(IncrementalMarkingClearsPolymorphicIC) { |
3388 if (i::FLAG_always_opt) return; | 3427 if (i::FLAG_always_opt) return; |
3389 CcTest::InitializeVM(); | 3428 CcTest::InitializeVM(); |
3390 v8::HandleScope scope(CcTest::isolate()); | 3429 v8::HandleScope scope(CcTest::isolate()); |
3391 v8::Local<v8::Value> obj1, obj2; | 3430 v8::Local<v8::Value> obj1, obj2; |
3392 | 3431 |
3393 { | 3432 { |
(...skipping 12 matching lines...) Expand all Loading... | |
3406 // originating from two different native contexts. | 3445 // originating from two different native contexts. |
3407 CcTest::global()->Set(v8_str("obj1"), obj1); | 3446 CcTest::global()->Set(v8_str("obj1"), obj1); |
3408 CcTest::global()->Set(v8_str("obj2"), obj2); | 3447 CcTest::global()->Set(v8_str("obj2"), obj2); |
3409 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);"); | 3448 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);"); |
3410 Handle<JSFunction> f = | 3449 Handle<JSFunction> f = |
3411 v8::Utils::OpenHandle( | 3450 v8::Utils::OpenHandle( |
3412 *v8::Handle<v8::Function>::Cast( | 3451 *v8::Handle<v8::Function>::Cast( |
3413 CcTest::global()->Get(v8_str("f")))); | 3452 CcTest::global()->Get(v8_str("f")))); |
3414 | 3453 |
3415 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); | 3454 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); |
3416 CHECK(ic_before->ic_state() == POLYMORPHIC); | 3455 if (FLAG_vector_ics) { |
3456 CheckVectorIC(f, 0, POLYMORPHIC); | |
Jakob Kummerow
2014/11/26 15:14:15
I guess this is a bug here then, since POLYMORPHIC
mvstanton
2014/11/27 13:09:27
Okay, CheckVectorIC() fixed. I did some hasty refa
| |
3457 CHECK(ic_before->ic_state() == DEFAULT); | |
3458 } else { | |
3459 CHECK(ic_before->ic_state() == POLYMORPHIC); | |
3460 } | |
3417 | 3461 |
3418 // Fire context dispose notification. | 3462 // Fire context dispose notification. |
3419 CcTest::isolate()->ContextDisposedNotification(); | 3463 CcTest::isolate()->ContextDisposedNotification(); |
3420 SimulateIncrementalMarking(CcTest::heap()); | 3464 SimulateIncrementalMarking(CcTest::heap()); |
3421 CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); | 3465 CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); |
3422 | 3466 |
3423 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); | 3467 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); |
3424 CHECK(IC::IsCleared(ic_after)); | 3468 if (FLAG_vector_ics) { |
3469 CheckVectorICCleared(f, 0); | |
3470 CHECK(ic_before->ic_state() == DEFAULT); | |
3471 } else { | |
3472 CHECK(IC::IsCleared(ic_after)); | |
3473 } | |
3425 } | 3474 } |
3426 | 3475 |
3427 | 3476 |
3428 class SourceResource : public v8::String::ExternalOneByteStringResource { | 3477 class SourceResource : public v8::String::ExternalOneByteStringResource { |
3429 public: | 3478 public: |
3430 explicit SourceResource(const char* data) | 3479 explicit SourceResource(const char* data) |
3431 : data_(data), length_(strlen(data)) { } | 3480 : data_(data), length_(strlen(data)) { } |
3432 | 3481 |
3433 virtual void Dispose() { | 3482 virtual void Dispose() { |
3434 i::DeleteArray(data_); | 3483 i::DeleteArray(data_); |
(...skipping 605 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4040 CcTest::global()->Get(v8_str("bar")))); | 4089 CcTest::global()->Get(v8_str("bar")))); |
4041 CHECK_EQ(bar_handle->code(), function_bar); | 4090 CHECK_EQ(bar_handle->code(), function_bar); |
4042 } | 4091 } |
4043 | 4092 |
4044 // Now make sure that a gc should get rid of the function, even though we | 4093 // Now make sure that a gc should get rid of the function, even though we |
4045 // still have the allocation site alive. | 4094 // still have the allocation site alive. |
4046 for (int i = 0; i < 4; i++) { | 4095 for (int i = 0; i < 4; i++) { |
4047 heap->CollectAllGarbage(Heap::kNoGCFlags); | 4096 heap->CollectAllGarbage(Heap::kNoGCFlags); |
4048 } | 4097 } |
4049 | 4098 |
4099 // TODO(mvstanton): this test fails when FLAG_vector_ics is true because | |
4100 // monomorphic load ics are preserved, but also strongly walked. They | |
4101 // end up keeping function bar alive. | |
4102 | |
4050 // The site still exists because of our global handle, but the code is no | 4103 // The site still exists because of our global handle, but the code is no |
4051 // longer referred to by dependent_code(). | 4104 // longer referred to by dependent_code(). |
4052 DependentCode::GroupStartIndexes starts(site->dependent_code()); | 4105 DependentCode::GroupStartIndexes starts(site->dependent_code()); |
4053 int index = starts.at(DependentCode::kAllocationSiteTransitionChangedGroup); | 4106 int index = starts.at(DependentCode::kAllocationSiteTransitionChangedGroup); |
4054 CHECK(!(site->dependent_code()->is_code_at(index))); | 4107 CHECK(!(site->dependent_code()->is_code_at(index))); |
4055 } | 4108 } |
4056 | 4109 |
4057 | 4110 |
4058 TEST(CellsInOptimizedCodeAreWeak) { | 4111 TEST(CellsInOptimizedCodeAreWeak) { |
4059 if (i::FLAG_always_opt || !i::FLAG_crankshaft) return; | 4112 if (i::FLAG_always_opt || !i::FLAG_crankshaft) return; |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4304 garbage.SetWeak(static_cast<void*>(&garbage), &ClearWeakIC); | 4357 garbage.SetWeak(static_cast<void*>(&garbage), &ClearWeakIC); |
4305 Heap* heap = CcTest::i_isolate()->heap(); | 4358 Heap* heap = CcTest::i_isolate()->heap(); |
4306 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); | 4359 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
4307 CHECK(weak_ic_cleared); | 4360 CHECK(weak_ic_cleared); |
4308 } | 4361 } |
4309 | 4362 |
4310 | 4363 |
4311 // Each of the following "weak IC" tests creates an IC that embeds a map with | 4364 // Each of the following "weak IC" tests creates an IC that embeds a map with |
4312 // the prototype pointing to _proto_ and checks that the _proto_ dies on GC. | 4365 // the prototype pointing to _proto_ and checks that the _proto_ dies on GC. |
4313 TEST(WeakMapInMonomorphicLoadIC) { | 4366 TEST(WeakMapInMonomorphicLoadIC) { |
4367 // TODO(mvstanton): vector ics need weak support! | |
4368 if (FLAG_vector_ics) return; | |
4314 CheckWeakness("function loadIC(obj) {" | 4369 CheckWeakness("function loadIC(obj) {" |
4315 " return obj.name;" | 4370 " return obj.name;" |
4316 "}" | 4371 "}" |
4317 " (function() {" | 4372 " (function() {" |
4318 " var proto = {'name' : 'weak'};" | 4373 " var proto = {'name' : 'weak'};" |
4319 " var obj = Object.create(proto);" | 4374 " var obj = Object.create(proto);" |
4320 " loadIC(obj);" | 4375 " loadIC(obj);" |
4321 " loadIC(obj);" | 4376 " loadIC(obj);" |
4322 " loadIC(obj);" | 4377 " loadIC(obj);" |
4323 " return proto;" | 4378 " return proto;" |
4324 " })();"); | 4379 " })();"); |
4325 } | 4380 } |
4326 | 4381 |
4327 | 4382 |
4328 TEST(WeakMapInMonomorphicKeyedLoadIC) { | 4383 TEST(WeakMapInMonomorphicKeyedLoadIC) { |
4384 // TODO(mvstanton): vector ics need weak support! | |
4385 if (FLAG_vector_ics) return; | |
4329 CheckWeakness("function keyedLoadIC(obj, field) {" | 4386 CheckWeakness("function keyedLoadIC(obj, field) {" |
4330 " return obj[field];" | 4387 " return obj[field];" |
4331 "}" | 4388 "}" |
4332 " (function() {" | 4389 " (function() {" |
4333 " var proto = {'name' : 'weak'};" | 4390 " var proto = {'name' : 'weak'};" |
4334 " var obj = Object.create(proto);" | 4391 " var obj = Object.create(proto);" |
4335 " keyedLoadIC(obj, 'name');" | 4392 " keyedLoadIC(obj, 'name');" |
4336 " keyedLoadIC(obj, 'name');" | 4393 " keyedLoadIC(obj, 'name');" |
4337 " keyedLoadIC(obj, 'name');" | 4394 " keyedLoadIC(obj, 'name');" |
4338 " return proto;" | 4395 " return proto;" |
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4755 #ifdef DEBUG | 4812 #ifdef DEBUG |
4756 TEST(PathTracer) { | 4813 TEST(PathTracer) { |
4757 CcTest::InitializeVM(); | 4814 CcTest::InitializeVM(); |
4758 v8::HandleScope scope(CcTest::isolate()); | 4815 v8::HandleScope scope(CcTest::isolate()); |
4759 | 4816 |
4760 v8::Local<v8::Value> result = CompileRun("'abc'"); | 4817 v8::Local<v8::Value> result = CompileRun("'abc'"); |
4761 Handle<Object> o = v8::Utils::OpenHandle(*result); | 4818 Handle<Object> o = v8::Utils::OpenHandle(*result); |
4762 CcTest::i_isolate()->heap()->TracePathToObject(*o); | 4819 CcTest::i_isolate()->heap()->TracePathToObject(*o); |
4763 } | 4820 } |
4764 #endif // DEBUG | 4821 #endif // DEBUG |
OLD | NEW |