| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 | 2 |
| 3 #include <stdlib.h> | 3 #include <stdlib.h> |
| 4 | 4 |
| 5 #include "v8.h" | 5 #include "v8.h" |
| 6 | 6 |
| 7 #include "compilation-cache.h" | |
| 8 #include "execution.h" | 7 #include "execution.h" |
| 9 #include "factory.h" | 8 #include "factory.h" |
| 10 #include "macro-assembler.h" | 9 #include "macro-assembler.h" |
| 11 #include "global-handles.h" | 10 #include "global-handles.h" |
| 12 #include "cctest.h" | 11 #include "cctest.h" |
| 13 | 12 |
| 14 using namespace v8::internal; | 13 using namespace v8::internal; |
| 15 | 14 |
| 16 static v8::Persistent<v8::Context> env; | 15 static v8::Persistent<v8::Context> env; |
| 17 | 16 |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 // nan oddball checks | 150 // nan oddball checks |
| 152 CHECK(HEAP->nan_value()->IsNumber()); | 151 CHECK(HEAP->nan_value()->IsNumber()); |
| 153 CHECK(isnan(HEAP->nan_value()->Number())); | 152 CHECK(isnan(HEAP->nan_value()->Number())); |
| 154 | 153 |
| 155 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest ")); | 154 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest ")); |
| 156 CHECK(s->IsString()); | 155 CHECK(s->IsString()); |
| 157 CHECK_EQ(10, s->length()); | 156 CHECK_EQ(10, s->length()); |
| 158 | 157 |
| 159 String* object_symbol = String::cast(HEAP->Object_symbol()); | 158 String* object_symbol = String::cast(HEAP->Object_symbol()); |
| 160 CHECK( | 159 CHECK( |
| 161 Isolate::Current()->context()->global_object()->HasLocalProperty( | 160 Isolate::Current()->context()->global()->HasLocalProperty(object_symbol)); |
| 162 object_symbol)); | |
| 163 | 161 |
| 164 // Check ToString for oddballs | 162 // Check ToString for oddballs |
| 165 CheckOddball(HEAP->true_value(), "true"); | 163 CheckOddball(HEAP->true_value(), "true"); |
| 166 CheckOddball(HEAP->false_value(), "false"); | 164 CheckOddball(HEAP->false_value(), "false"); |
| 167 CheckOddball(HEAP->null_value(), "null"); | 165 CheckOddball(HEAP->null_value(), "null"); |
| 168 CheckOddball(HEAP->undefined_value(), "undefined"); | 166 CheckOddball(HEAP->undefined_value(), "undefined"); |
| 169 | 167 |
| 170 // Check ToString for Smis | 168 // Check ToString for Smis |
| 171 CheckSmi(0, "0"); | 169 CheckSmi(0, "0"); |
| 172 CheckSmi(42, "42"); | 170 CheckSmi(42, "42"); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 Handle<String> obj_name = FACTORY->LookupAsciiSymbol("theObject"); | 206 Handle<String> obj_name = FACTORY->LookupAsciiSymbol("theObject"); |
| 209 | 207 |
| 210 { | 208 { |
| 211 v8::HandleScope inner_scope; | 209 v8::HandleScope inner_scope; |
| 212 // Allocate a function and keep it in global object's property. | 210 // Allocate a function and keep it in global object's property. |
| 213 Handle<JSFunction> function = | 211 Handle<JSFunction> function = |
| 214 FACTORY->NewFunction(name, FACTORY->undefined_value()); | 212 FACTORY->NewFunction(name, FACTORY->undefined_value()); |
| 215 Handle<Map> initial_map = | 213 Handle<Map> initial_map = |
| 216 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); | 214 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); |
| 217 function->set_initial_map(*initial_map); | 215 function->set_initial_map(*initial_map); |
| 218 Isolate::Current()->context()->global_object()->SetProperty( | 216 Isolate::Current()->context()->global()->SetProperty( |
| 219 *name, *function, NONE, kNonStrictMode)->ToObjectChecked(); | 217 *name, *function, NONE, kNonStrictMode)->ToObjectChecked(); |
| 220 // Allocate an object. Unrooted after leaving the scope. | 218 // Allocate an object. Unrooted after leaving the scope. |
| 221 Handle<JSObject> obj = FACTORY->NewJSObject(function); | 219 Handle<JSObject> obj = FACTORY->NewJSObject(function); |
| 222 obj->SetProperty( | 220 obj->SetProperty( |
| 223 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked(); | 221 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked(); |
| 224 obj->SetProperty( | 222 obj->SetProperty( |
| 225 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked(); | 223 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked(); |
| 226 | 224 |
| 227 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name)); | 225 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name)); |
| 228 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex)); | 226 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex)); |
| 229 } | 227 } |
| 230 | 228 |
| 231 HEAP->CollectGarbage(NEW_SPACE); | 229 HEAP->CollectGarbage(NEW_SPACE); |
| 232 | 230 |
| 233 // Function should be alive. | 231 // Function should be alive. |
| 234 CHECK(Isolate::Current()->context()->global_object()-> | 232 CHECK(Isolate::Current()->context()->global()->HasLocalProperty(*name)); |
| 235 HasLocalProperty(*name)); | |
| 236 // Check function is retained. | 233 // Check function is retained. |
| 237 Object* func_value = Isolate::Current()->context()->global_object()-> | 234 Object* func_value = Isolate::Current()->context()->global()-> |
| 238 GetProperty(*name)->ToObjectChecked(); | 235 GetProperty(*name)->ToObjectChecked(); |
| 239 CHECK(func_value->IsJSFunction()); | 236 CHECK(func_value->IsJSFunction()); |
| 240 Handle<JSFunction> function(JSFunction::cast(func_value)); | 237 Handle<JSFunction> function(JSFunction::cast(func_value)); |
| 241 | 238 |
| 242 { | 239 { |
| 243 HandleScope inner_scope; | 240 HandleScope inner_scope; |
| 244 // Allocate another object, make it reachable from global. | 241 // Allocate another object, make it reachable from global. |
| 245 Handle<JSObject> obj = FACTORY->NewJSObject(function); | 242 Handle<JSObject> obj = FACTORY->NewJSObject(function); |
| 246 Isolate::Current()->context()->global_object()->SetProperty( | 243 Isolate::Current()->context()->global()->SetProperty( |
| 247 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked(); | 244 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked(); |
| 248 obj->SetProperty( | 245 obj->SetProperty( |
| 249 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked(); | 246 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked(); |
| 250 } | 247 } |
| 251 | 248 |
| 252 // After gc, it should survive. | 249 // After gc, it should survive. |
| 253 HEAP->CollectGarbage(NEW_SPACE); | 250 HEAP->CollectGarbage(NEW_SPACE); |
| 254 | 251 |
| 255 CHECK(Isolate::Current()->context()->global_object()-> | 252 CHECK(Isolate::Current()->context()->global()->HasLocalProperty(*obj_name)); |
| 256 HasLocalProperty(*obj_name)); | 253 CHECK(Isolate::Current()->context()->global()-> |
| 257 CHECK(Isolate::Current()->context()->global_object()-> | |
| 258 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject()); | 254 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject()); |
| 259 Object* obj = Isolate::Current()->context()->global_object()-> | 255 Object* obj = Isolate::Current()->context()->global()-> |
| 260 GetProperty(*obj_name)->ToObjectChecked(); | 256 GetProperty(*obj_name)->ToObjectChecked(); |
| 261 JSObject* js_obj = JSObject::cast(obj); | 257 JSObject* js_obj = JSObject::cast(obj); |
| 262 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name)); | 258 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name)); |
| 263 } | 259 } |
| 264 | 260 |
| 265 | 261 |
| 266 static void VerifyStringAllocation(const char* string) { | 262 static void VerifyStringAllocation(const char* string) { |
| 267 v8::HandleScope scope; | 263 v8::HandleScope scope; |
| 268 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string)); | 264 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string)); |
| 269 CHECK_EQ(StrLength(string), s->length()); | 265 CHECK_EQ(StrLength(string), s->length()); |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 560 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked(); | 556 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked(); |
| 561 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name)); | 557 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name)); |
| 562 } | 558 } |
| 563 | 559 |
| 564 | 560 |
| 565 TEST(ObjectProperties) { | 561 TEST(ObjectProperties) { |
| 566 InitializeVM(); | 562 InitializeVM(); |
| 567 | 563 |
| 568 v8::HandleScope sc; | 564 v8::HandleScope sc; |
| 569 String* object_symbol = String::cast(HEAP->Object_symbol()); | 565 String* object_symbol = String::cast(HEAP->Object_symbol()); |
| 570 Object* raw_object = Isolate::Current()->context()->global_object()-> | 566 Object* raw_object = Isolate::Current()->context()->global()-> |
| 571 GetProperty(object_symbol)->ToObjectChecked(); | 567 GetProperty(object_symbol)->ToObjectChecked(); |
| 572 JSFunction* object_function = JSFunction::cast(raw_object); | 568 JSFunction* object_function = JSFunction::cast(raw_object); |
| 573 Handle<JSFunction> constructor(object_function); | 569 Handle<JSFunction> constructor(object_function); |
| 574 Handle<JSObject> obj = FACTORY->NewJSObject(constructor); | 570 Handle<JSObject> obj = FACTORY->NewJSObject(constructor); |
| 575 Handle<String> first = FACTORY->LookupAsciiSymbol("first"); | 571 Handle<String> first = FACTORY->LookupAsciiSymbol("first"); |
| 576 Handle<String> second = FACTORY->LookupAsciiSymbol("second"); | 572 Handle<String> second = FACTORY->LookupAsciiSymbol("second"); |
| 577 | 573 |
| 578 // check for empty | 574 // check for empty |
| 579 CHECK(!obj->HasLocalProperty(*first)); | 575 CHECK(!obj->HasLocalProperty(*first)); |
| 580 | 576 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 657 // Check the map has changed | 653 // Check the map has changed |
| 658 CHECK(*initial_map != obj->map()); | 654 CHECK(*initial_map != obj->map()); |
| 659 } | 655 } |
| 660 | 656 |
| 661 | 657 |
| 662 TEST(JSArray) { | 658 TEST(JSArray) { |
| 663 InitializeVM(); | 659 InitializeVM(); |
| 664 | 660 |
| 665 v8::HandleScope sc; | 661 v8::HandleScope sc; |
| 666 Handle<String> name = FACTORY->LookupAsciiSymbol("Array"); | 662 Handle<String> name = FACTORY->LookupAsciiSymbol("Array"); |
| 667 Object* raw_object = Isolate::Current()->context()->global_object()-> | 663 Object* raw_object = Isolate::Current()->context()->global()-> |
| 668 GetProperty(*name)->ToObjectChecked(); | 664 GetProperty(*name)->ToObjectChecked(); |
| 669 Handle<JSFunction> function = Handle<JSFunction>( | 665 Handle<JSFunction> function = Handle<JSFunction>( |
| 670 JSFunction::cast(raw_object)); | 666 JSFunction::cast(raw_object)); |
| 671 | 667 |
| 672 // Allocate the object. | 668 // Allocate the object. |
| 673 Handle<JSObject> object = FACTORY->NewJSObject(function); | 669 Handle<JSObject> object = FACTORY->NewJSObject(function); |
| 674 Handle<JSArray> array = Handle<JSArray>::cast(object); | 670 Handle<JSArray> array = Handle<JSArray>::cast(object); |
| 675 // We just initialized the VM, no heap allocation failure yet. | 671 // We just initialized the VM, no heap allocation failure yet. |
| 676 array->Initialize(0)->ToObjectChecked(); | 672 array->Initialize(0)->ToObjectChecked(); |
| 677 | 673 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 704 CHECK_EQ(array->GetElement(int_length), *name); | 700 CHECK_EQ(array->GetElement(int_length), *name); |
| 705 CHECK_EQ(array->GetElement(0), *name); | 701 CHECK_EQ(array->GetElement(0), *name); |
| 706 } | 702 } |
| 707 | 703 |
| 708 | 704 |
| 709 TEST(JSObjectCopy) { | 705 TEST(JSObjectCopy) { |
| 710 InitializeVM(); | 706 InitializeVM(); |
| 711 | 707 |
| 712 v8::HandleScope sc; | 708 v8::HandleScope sc; |
| 713 String* object_symbol = String::cast(HEAP->Object_symbol()); | 709 String* object_symbol = String::cast(HEAP->Object_symbol()); |
| 714 Object* raw_object = Isolate::Current()->context()->global_object()-> | 710 Object* raw_object = Isolate::Current()->context()->global()-> |
| 715 GetProperty(object_symbol)->ToObjectChecked(); | 711 GetProperty(object_symbol)->ToObjectChecked(); |
| 716 JSFunction* object_function = JSFunction::cast(raw_object); | 712 JSFunction* object_function = JSFunction::cast(raw_object); |
| 717 Handle<JSFunction> constructor(object_function); | 713 Handle<JSFunction> constructor(object_function); |
| 718 Handle<JSObject> obj = FACTORY->NewJSObject(constructor); | 714 Handle<JSObject> obj = FACTORY->NewJSObject(constructor); |
| 719 Handle<String> first = FACTORY->LookupAsciiSymbol("first"); | 715 Handle<String> first = FACTORY->LookupAsciiSymbol("first"); |
| 720 Handle<String> second = FACTORY->LookupAsciiSymbol("second"); | 716 Handle<String> second = FACTORY->LookupAsciiSymbol("second"); |
| 721 | 717 |
| 722 obj->SetProperty( | 718 obj->SetProperty( |
| 723 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); | 719 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); |
| 724 obj->SetProperty( | 720 obj->SetProperty( |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 873 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | 869 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
| 874 | 870 |
| 875 v8::HandleScope scope; | 871 v8::HandleScope scope; |
| 876 | 872 |
| 877 // The plan: create JSObject which references objects in new space. | 873 // The plan: create JSObject which references objects in new space. |
| 878 // Then clone this object (forcing it to go into old space) and check | 874 // Then clone this object (forcing it to go into old space) and check |
| 879 // that region dirty marks are updated correctly. | 875 // that region dirty marks are updated correctly. |
| 880 | 876 |
| 881 // Step 1: prepare a map for the object. We add 1 inobject property to it. | 877 // Step 1: prepare a map for the object. We add 1 inobject property to it. |
| 882 Handle<JSFunction> object_ctor( | 878 Handle<JSFunction> object_ctor( |
| 883 Isolate::Current()->native_context()->object_function()); | 879 Isolate::Current()->global_context()->object_function()); |
| 884 CHECK(object_ctor->has_initial_map()); | 880 CHECK(object_ctor->has_initial_map()); |
| 885 Handle<Map> object_map(object_ctor->initial_map()); | 881 Handle<Map> object_map(object_ctor->initial_map()); |
| 886 // Create a map with single inobject property. | 882 // Create a map with single inobject property. |
| 887 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1); | 883 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1); |
| 888 int n_properties = my_map->inobject_properties(); | 884 int n_properties = my_map->inobject_properties(); |
| 889 CHECK_GT(n_properties, 0); | 885 CHECK_GT(n_properties, 0); |
| 890 | 886 |
| 891 int object_size = my_map->instance_size(); | 887 int object_size = my_map->instance_size(); |
| 892 | 888 |
| 893 // Step 2: allocate a lot of objects so to almost fill new space: we need | 889 // Step 2: allocate a lot of objects so to almost fill new space: we need |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 953 "};" | 949 "};" |
| 954 "foo()"; | 950 "foo()"; |
| 955 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo"); | 951 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo"); |
| 956 | 952 |
| 957 // This compile will add the code to the compilation cache. | 953 // This compile will add the code to the compilation cache. |
| 958 { v8::HandleScope scope; | 954 { v8::HandleScope scope; |
| 959 CompileRun(source); | 955 CompileRun(source); |
| 960 } | 956 } |
| 961 | 957 |
| 962 // Check function is compiled. | 958 // Check function is compiled. |
| 963 Object* func_value = Isolate::Current()->context()->global_object()-> | 959 Object* func_value = Isolate::Current()->context()->global()-> |
| 964 GetProperty(*foo_name)->ToObjectChecked(); | 960 GetProperty(*foo_name)->ToObjectChecked(); |
| 965 CHECK(func_value->IsJSFunction()); | 961 CHECK(func_value->IsJSFunction()); |
| 966 Handle<JSFunction> function(JSFunction::cast(func_value)); | 962 Handle<JSFunction> function(JSFunction::cast(func_value)); |
| 967 CHECK(function->shared()->is_compiled()); | 963 CHECK(function->shared()->is_compiled()); |
| 968 | 964 |
| 969 // TODO(1609) Currently incremental marker does not support code flushing. | 965 // TODO(1609) Currently incremental marker does not support code flushing. |
| 970 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); | 966 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
| 971 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); | 967 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
| 972 | 968 |
| 973 CHECK(function->shared()->is_compiled()); | 969 CHECK(function->shared()->is_compiled()); |
| 974 | 970 |
| 975 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); | 971 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
| 976 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); | 972 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
| 977 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); | 973 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
| 978 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); | 974 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
| 979 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); | 975 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
| 980 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); | 976 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
| 981 | 977 |
| 982 // foo should no longer be in the compilation cache | 978 // foo should no longer be in the compilation cache |
| 983 CHECK(!function->shared()->is_compiled() || function->IsOptimized()); | 979 CHECK(!function->shared()->is_compiled() || function->IsOptimized()); |
| 984 CHECK(!function->is_compiled() || function->IsOptimized()); | 980 CHECK(!function->is_compiled() || function->IsOptimized()); |
| 985 // Call foo to get it recompiled. | 981 // Call foo to get it recompiled. |
| 986 CompileRun("foo()"); | 982 CompileRun("foo()"); |
| 987 CHECK(function->shared()->is_compiled()); | 983 CHECK(function->shared()->is_compiled()); |
| 988 CHECK(function->is_compiled()); | 984 CHECK(function->is_compiled()); |
| 989 } | 985 } |
| 990 | 986 |
| 991 | 987 |
| 992 // Count the number of native contexts in the weak list of native contexts. | 988 // Count the number of global contexts in the weak list of global contexts. |
| 993 int CountNativeContexts() { | 989 int CountGlobalContexts() { |
| 994 int count = 0; | 990 int count = 0; |
| 995 Object* object = HEAP->native_contexts_list(); | 991 Object* object = HEAP->global_contexts_list(); |
| 996 while (!object->IsUndefined()) { | 992 while (!object->IsUndefined()) { |
| 997 count++; | 993 count++; |
| 998 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK); | 994 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK); |
| 999 } | 995 } |
| 1000 return count; | 996 return count; |
| 1001 } | 997 } |
| 1002 | 998 |
| 1003 | 999 |
| 1004 // Count the number of user functions in the weak list of optimized | 1000 // Count the number of user functions in the weak list of optimized |
| 1005 // functions attached to a native context. | 1001 // functions attached to a global context. |
| 1006 static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) { | 1002 static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) { |
| 1007 int count = 0; | 1003 int count = 0; |
| 1008 Handle<Context> icontext = v8::Utils::OpenHandle(*context); | 1004 Handle<Context> icontext = v8::Utils::OpenHandle(*context); |
| 1009 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST); | 1005 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST); |
| 1010 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) { | 1006 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) { |
| 1011 count++; | 1007 count++; |
| 1012 object = JSFunction::cast(object)->next_function_link(); | 1008 object = JSFunction::cast(object)->next_function_link(); |
| 1013 } | 1009 } |
| 1014 return count; | 1010 return count; |
| 1015 } | 1011 } |
| 1016 | 1012 |
| 1017 | 1013 |
| 1018 TEST(TestInternalWeakLists) { | 1014 TEST(TestInternalWeakLists) { |
| 1019 v8::V8::Initialize(); | 1015 v8::V8::Initialize(); |
| 1020 | 1016 |
| 1021 static const int kNumTestContexts = 10; | 1017 static const int kNumTestContexts = 10; |
| 1022 | 1018 |
| 1023 v8::HandleScope scope; | 1019 v8::HandleScope scope; |
| 1024 v8::Persistent<v8::Context> ctx[kNumTestContexts]; | 1020 v8::Persistent<v8::Context> ctx[kNumTestContexts]; |
| 1025 | 1021 |
| 1026 CHECK_EQ(0, CountNativeContexts()); | 1022 CHECK_EQ(0, CountGlobalContexts()); |
| 1027 | 1023 |
| 1028 // Create a number of global contests which gets linked together. | 1024 // Create a number of global contests which gets linked together. |
| 1029 for (int i = 0; i < kNumTestContexts; i++) { | 1025 for (int i = 0; i < kNumTestContexts; i++) { |
| 1030 ctx[i] = v8::Context::New(); | 1026 ctx[i] = v8::Context::New(); |
| 1031 | 1027 |
| 1032 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft()); | 1028 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft()); |
| 1033 | 1029 |
| 1034 CHECK_EQ(i + 1, CountNativeContexts()); | 1030 CHECK_EQ(i + 1, CountGlobalContexts()); |
| 1035 | 1031 |
| 1036 ctx[i]->Enter(); | 1032 ctx[i]->Enter(); |
| 1037 | 1033 |
| 1038 // Create a handle scope so no function objects get stuch in the outer | 1034 // Create a handle scope so no function objects get stuch in the outer |
| 1039 // handle scope | 1035 // handle scope |
| 1040 v8::HandleScope scope; | 1036 v8::HandleScope scope; |
| 1041 const char* source = "function f1() { };" | 1037 const char* source = "function f1() { };" |
| 1042 "function f2() { };" | 1038 "function f2() { };" |
| 1043 "function f3() { };" | 1039 "function f3() { };" |
| 1044 "function f4() { };" | 1040 "function f4() { };" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1059 // Remove function f1, and | 1055 // Remove function f1, and |
| 1060 CompileRun("f1=null"); | 1056 CompileRun("f1=null"); |
| 1061 | 1057 |
| 1062 // Scavenge treats these references as strong. | 1058 // Scavenge treats these references as strong. |
| 1063 for (int j = 0; j < 10; j++) { | 1059 for (int j = 0; j < 10; j++) { |
| 1064 HEAP->PerformScavenge(); | 1060 HEAP->PerformScavenge(); |
| 1065 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i])); | 1061 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i])); |
| 1066 } | 1062 } |
| 1067 | 1063 |
| 1068 // Mark compact handles the weak references. | 1064 // Mark compact handles the weak references. |
| 1069 ISOLATE->compilation_cache()->Clear(); | |
| 1070 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | 1065 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
| 1071 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); | 1066 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); |
| 1072 | 1067 |
| 1073 // Get rid of f3 and f5 in the same way. | 1068 // Get rid of f3 and f5 in the same way. |
| 1074 CompileRun("f3=null"); | 1069 CompileRun("f3=null"); |
| 1075 for (int j = 0; j < 10; j++) { | 1070 for (int j = 0; j < 10; j++) { |
| 1076 HEAP->PerformScavenge(); | 1071 HEAP->PerformScavenge(); |
| 1077 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); | 1072 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); |
| 1078 } | 1073 } |
| 1079 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | 1074 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
| 1080 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); | 1075 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); |
| 1081 CompileRun("f5=null"); | 1076 CompileRun("f5=null"); |
| 1082 for (int j = 0; j < 10; j++) { | 1077 for (int j = 0; j < 10; j++) { |
| 1083 HEAP->PerformScavenge(); | 1078 HEAP->PerformScavenge(); |
| 1084 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); | 1079 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); |
| 1085 } | 1080 } |
| 1086 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | 1081 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
| 1087 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i])); | 1082 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i])); |
| 1088 | 1083 |
| 1089 ctx[i]->Exit(); | 1084 ctx[i]->Exit(); |
| 1090 } | 1085 } |
| 1091 | 1086 |
| 1092 // Force compilation cache cleanup. | 1087 // Force compilation cache cleanup. |
| 1093 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | 1088 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
| 1094 | 1089 |
| 1095 // Dispose the native contexts one by one. | 1090 // Dispose the global contexts one by one. |
| 1096 for (int i = 0; i < kNumTestContexts; i++) { | 1091 for (int i = 0; i < kNumTestContexts; i++) { |
| 1097 ctx[i].Dispose(); | 1092 ctx[i].Dispose(); |
| 1098 ctx[i].Clear(); | 1093 ctx[i].Clear(); |
| 1099 | 1094 |
| 1100 // Scavenge treats these references as strong. | 1095 // Scavenge treats these references as strong. |
| 1101 for (int j = 0; j < 10; j++) { | 1096 for (int j = 0; j < 10; j++) { |
| 1102 HEAP->PerformScavenge(); | 1097 HEAP->PerformScavenge(); |
| 1103 CHECK_EQ(kNumTestContexts - i, CountNativeContexts()); | 1098 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts()); |
| 1104 } | 1099 } |
| 1105 | 1100 |
| 1106 // Mark compact handles the weak references. | 1101 // Mark compact handles the weak references. |
| 1107 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | 1102 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
| 1108 CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts()); | 1103 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts()); |
| 1109 } | 1104 } |
| 1110 | 1105 |
| 1111 CHECK_EQ(0, CountNativeContexts()); | 1106 CHECK_EQ(0, CountGlobalContexts()); |
| 1112 } | 1107 } |
| 1113 | 1108 |
| 1114 | 1109 |
| 1115 // Count the number of native contexts in the weak list of native contexts | 1110 // Count the number of global contexts in the weak list of global contexts |
| 1116 // causing a GC after the specified number of elements. | 1111 // causing a GC after the specified number of elements. |
| 1117 static int CountNativeContextsWithGC(int n) { | 1112 static int CountGlobalContextsWithGC(int n) { |
| 1118 int count = 0; | 1113 int count = 0; |
| 1119 Handle<Object> object(HEAP->native_contexts_list()); | 1114 Handle<Object> object(HEAP->global_contexts_list()); |
| 1120 while (!object->IsUndefined()) { | 1115 while (!object->IsUndefined()) { |
| 1121 count++; | 1116 count++; |
| 1122 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags); | 1117 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
| 1123 object = | 1118 object = |
| 1124 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK)); | 1119 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK)); |
| 1125 } | 1120 } |
| 1126 return count; | 1121 return count; |
| 1127 } | 1122 } |
| 1128 | 1123 |
| 1129 | 1124 |
| 1130 // Count the number of user functions in the weak list of optimized | 1125 // Count the number of user functions in the weak list of optimized |
| 1131 // functions attached to a native context causing a GC after the | 1126 // functions attached to a global context causing a GC after the |
| 1132 // specified number of elements. | 1127 // specified number of elements. |
| 1133 static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context, | 1128 static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context, |
| 1134 int n) { | 1129 int n) { |
| 1135 int count = 0; | 1130 int count = 0; |
| 1136 Handle<Context> icontext = v8::Utils::OpenHandle(*context); | 1131 Handle<Context> icontext = v8::Utils::OpenHandle(*context); |
| 1137 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST)); | 1132 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST)); |
| 1138 while (object->IsJSFunction() && | 1133 while (object->IsJSFunction() && |
| 1139 !Handle<JSFunction>::cast(object)->IsBuiltin()) { | 1134 !Handle<JSFunction>::cast(object)->IsBuiltin()) { |
| 1140 count++; | 1135 count++; |
| 1141 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags); | 1136 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
| 1142 object = Handle<Object>( | 1137 object = Handle<Object>( |
| 1143 Object::cast(JSFunction::cast(*object)->next_function_link())); | 1138 Object::cast(JSFunction::cast(*object)->next_function_link())); |
| 1144 } | 1139 } |
| 1145 return count; | 1140 return count; |
| 1146 } | 1141 } |
| 1147 | 1142 |
| 1148 | 1143 |
| 1149 TEST(TestInternalWeakListsTraverseWithGC) { | 1144 TEST(TestInternalWeakListsTraverseWithGC) { |
| 1150 v8::V8::Initialize(); | 1145 v8::V8::Initialize(); |
| 1151 | 1146 |
| 1152 static const int kNumTestContexts = 10; | 1147 static const int kNumTestContexts = 10; |
| 1153 | 1148 |
| 1154 v8::HandleScope scope; | 1149 v8::HandleScope scope; |
| 1155 v8::Persistent<v8::Context> ctx[kNumTestContexts]; | 1150 v8::Persistent<v8::Context> ctx[kNumTestContexts]; |
| 1156 | 1151 |
| 1157 CHECK_EQ(0, CountNativeContexts()); | 1152 CHECK_EQ(0, CountGlobalContexts()); |
| 1158 | 1153 |
| 1159 // Create an number of contexts and check the length of the weak list both | 1154 // Create an number of contexts and check the length of the weak list both |
| 1160 // with and without GCs while iterating the list. | 1155 // with and without GCs while iterating the list. |
| 1161 for (int i = 0; i < kNumTestContexts; i++) { | 1156 for (int i = 0; i < kNumTestContexts; i++) { |
| 1162 ctx[i] = v8::Context::New(); | 1157 ctx[i] = v8::Context::New(); |
| 1163 CHECK_EQ(i + 1, CountNativeContexts()); | 1158 CHECK_EQ(i + 1, CountGlobalContexts()); |
| 1164 CHECK_EQ(i + 1, CountNativeContextsWithGC(i / 2 + 1)); | 1159 CHECK_EQ(i + 1, CountGlobalContextsWithGC(i / 2 + 1)); |
| 1165 } | 1160 } |
| 1166 | 1161 |
| 1167 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft()); | 1162 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft()); |
| 1168 | 1163 |
| 1169 // Compile a number of functions the length of the weak list of optimized | 1164 // Compile a number of functions the length of the weak list of optimized |
| 1170 // functions both with and without GCs while iterating the list. | 1165 // functions both with and without GCs while iterating the list. |
| 1171 ctx[0]->Enter(); | 1166 ctx[0]->Enter(); |
| 1172 const char* source = "function f1() { };" | 1167 const char* source = "function f1() { };" |
| 1173 "function f2() { };" | 1168 "function f2() { };" |
| 1174 "function f3() { };" | 1169 "function f3() { };" |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1364 HeapIterator iterator; | 1359 HeapIterator iterator; |
| 1365 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { | 1360 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { |
| 1366 if (obj->IsGlobalObject()) count++; | 1361 if (obj->IsGlobalObject()) count++; |
| 1367 } | 1362 } |
| 1368 return count; | 1363 return count; |
| 1369 } | 1364 } |
| 1370 | 1365 |
| 1371 | 1366 |
| 1372 // Test that we don't embed maps from foreign contexts into | 1367 // Test that we don't embed maps from foreign contexts into |
| 1373 // optimized code. | 1368 // optimized code. |
| 1374 TEST(LeakNativeContextViaMap) { | 1369 TEST(LeakGlobalContextViaMap) { |
| 1375 i::FLAG_allow_natives_syntax = true; | 1370 i::FLAG_allow_natives_syntax = true; |
| 1376 v8::HandleScope outer_scope; | 1371 v8::HandleScope outer_scope; |
| 1377 v8::Persistent<v8::Context> ctx1 = v8::Context::New(); | 1372 v8::Persistent<v8::Context> ctx1 = v8::Context::New(); |
| 1378 v8::Persistent<v8::Context> ctx2 = v8::Context::New(); | 1373 v8::Persistent<v8::Context> ctx2 = v8::Context::New(); |
| 1379 ctx1->Enter(); | 1374 ctx1->Enter(); |
| 1380 | 1375 |
| 1381 HEAP->CollectAllAvailableGarbage(); | 1376 HEAP->CollectAllAvailableGarbage(); |
| 1382 CHECK_EQ(4, NumberOfGlobalObjects()); | 1377 CHECK_EQ(4, NumberOfGlobalObjects()); |
| 1383 | 1378 |
| 1384 { | 1379 { |
| 1385 v8::HandleScope inner_scope; | 1380 v8::HandleScope inner_scope; |
| 1386 CompileRun("var v = {x: 42}"); | 1381 CompileRun("var v = {x: 42}"); |
| 1387 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v")); | 1382 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v")); |
| 1388 ctx2->Enter(); | 1383 ctx2->Enter(); |
| 1389 ctx2->Global()->Set(v8_str("o"), v); | 1384 ctx2->Global()->Set(v8_str("o"), v); |
| 1390 v8::Local<v8::Value> res = CompileRun( | 1385 v8::Local<v8::Value> res = CompileRun( |
| 1391 "function f() { return o.x; }" | 1386 "function f() { return o.x; }" |
| 1392 "for (var i = 0; i < 10; ++i) f();" | 1387 "for (var i = 0; i < 10; ++i) f();" |
| 1393 "%OptimizeFunctionOnNextCall(f);" | 1388 "%OptimizeFunctionOnNextCall(f);" |
| 1394 "f();"); | 1389 "f();"); |
| 1395 CHECK_EQ(42, res->Int32Value()); | 1390 CHECK_EQ(42, res->Int32Value()); |
| 1396 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0)); | 1391 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0)); |
| 1397 ctx2->Exit(); | 1392 ctx2->Exit(); |
| 1398 ctx1->Exit(); | 1393 ctx1->Exit(); |
| 1399 ctx1.Dispose(); | 1394 ctx1.Dispose(); |
| 1400 v8::V8::ContextDisposedNotification(); | |
| 1401 } | 1395 } |
| 1402 HEAP->CollectAllAvailableGarbage(); | 1396 HEAP->CollectAllAvailableGarbage(); |
| 1403 CHECK_EQ(2, NumberOfGlobalObjects()); | 1397 CHECK_EQ(2, NumberOfGlobalObjects()); |
| 1404 ctx2.Dispose(); | 1398 ctx2.Dispose(); |
| 1405 HEAP->CollectAllAvailableGarbage(); | 1399 HEAP->CollectAllAvailableGarbage(); |
| 1406 CHECK_EQ(0, NumberOfGlobalObjects()); | 1400 CHECK_EQ(0, NumberOfGlobalObjects()); |
| 1407 } | 1401 } |
| 1408 | 1402 |
| 1409 | 1403 |
| 1410 // Test that we don't embed functions from foreign contexts into | 1404 // Test that we don't embed functions from foreign contexts into |
| 1411 // optimized code. | 1405 // optimized code. |
| 1412 TEST(LeakNativeContextViaFunction) { | 1406 TEST(LeakGlobalContextViaFunction) { |
| 1413 i::FLAG_allow_natives_syntax = true; | 1407 i::FLAG_allow_natives_syntax = true; |
| 1414 v8::HandleScope outer_scope; | 1408 v8::HandleScope outer_scope; |
| 1415 v8::Persistent<v8::Context> ctx1 = v8::Context::New(); | 1409 v8::Persistent<v8::Context> ctx1 = v8::Context::New(); |
| 1416 v8::Persistent<v8::Context> ctx2 = v8::Context::New(); | 1410 v8::Persistent<v8::Context> ctx2 = v8::Context::New(); |
| 1417 ctx1->Enter(); | 1411 ctx1->Enter(); |
| 1418 | 1412 |
| 1419 HEAP->CollectAllAvailableGarbage(); | 1413 HEAP->CollectAllAvailableGarbage(); |
| 1420 CHECK_EQ(4, NumberOfGlobalObjects()); | 1414 CHECK_EQ(4, NumberOfGlobalObjects()); |
| 1421 | 1415 |
| 1422 { | 1416 { |
| 1423 v8::HandleScope inner_scope; | 1417 v8::HandleScope inner_scope; |
| 1424 CompileRun("var v = function() { return 42; }"); | 1418 CompileRun("var v = function() { return 42; }"); |
| 1425 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v")); | 1419 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v")); |
| 1426 ctx2->Enter(); | 1420 ctx2->Enter(); |
| 1427 ctx2->Global()->Set(v8_str("o"), v); | 1421 ctx2->Global()->Set(v8_str("o"), v); |
| 1428 v8::Local<v8::Value> res = CompileRun( | 1422 v8::Local<v8::Value> res = CompileRun( |
| 1429 "function f(x) { return x(); }" | 1423 "function f(x) { return x(); }" |
| 1430 "for (var i = 0; i < 10; ++i) f(o);" | 1424 "for (var i = 0; i < 10; ++i) f(o);" |
| 1431 "%OptimizeFunctionOnNextCall(f);" | 1425 "%OptimizeFunctionOnNextCall(f);" |
| 1432 "f(o);"); | 1426 "f(o);"); |
| 1433 CHECK_EQ(42, res->Int32Value()); | 1427 CHECK_EQ(42, res->Int32Value()); |
| 1434 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0)); | 1428 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0)); |
| 1435 ctx2->Exit(); | 1429 ctx2->Exit(); |
| 1436 ctx1->Exit(); | 1430 ctx1->Exit(); |
| 1437 ctx1.Dispose(); | 1431 ctx1.Dispose(); |
| 1438 v8::V8::ContextDisposedNotification(); | |
| 1439 } | 1432 } |
| 1440 HEAP->CollectAllAvailableGarbage(); | 1433 HEAP->CollectAllAvailableGarbage(); |
| 1441 CHECK_EQ(2, NumberOfGlobalObjects()); | 1434 CHECK_EQ(2, NumberOfGlobalObjects()); |
| 1442 ctx2.Dispose(); | 1435 ctx2.Dispose(); |
| 1443 HEAP->CollectAllAvailableGarbage(); | 1436 HEAP->CollectAllAvailableGarbage(); |
| 1444 CHECK_EQ(0, NumberOfGlobalObjects()); | 1437 CHECK_EQ(0, NumberOfGlobalObjects()); |
| 1445 } | 1438 } |
| 1446 | 1439 |
| 1447 | 1440 |
| 1448 TEST(LeakNativeContextViaMapKeyed) { | 1441 TEST(LeakGlobalContextViaMapKeyed) { |
| 1449 i::FLAG_allow_natives_syntax = true; | 1442 i::FLAG_allow_natives_syntax = true; |
| 1450 v8::HandleScope outer_scope; | 1443 v8::HandleScope outer_scope; |
| 1451 v8::Persistent<v8::Context> ctx1 = v8::Context::New(); | 1444 v8::Persistent<v8::Context> ctx1 = v8::Context::New(); |
| 1452 v8::Persistent<v8::Context> ctx2 = v8::Context::New(); | 1445 v8::Persistent<v8::Context> ctx2 = v8::Context::New(); |
| 1453 ctx1->Enter(); | 1446 ctx1->Enter(); |
| 1454 | 1447 |
| 1455 HEAP->CollectAllAvailableGarbage(); | 1448 HEAP->CollectAllAvailableGarbage(); |
| 1456 CHECK_EQ(4, NumberOfGlobalObjects()); | 1449 CHECK_EQ(4, NumberOfGlobalObjects()); |
| 1457 | 1450 |
| 1458 { | 1451 { |
| 1459 v8::HandleScope inner_scope; | 1452 v8::HandleScope inner_scope; |
| 1460 CompileRun("var v = [42, 43]"); | 1453 CompileRun("var v = [42, 43]"); |
| 1461 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v")); | 1454 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v")); |
| 1462 ctx2->Enter(); | 1455 ctx2->Enter(); |
| 1463 ctx2->Global()->Set(v8_str("o"), v); | 1456 ctx2->Global()->Set(v8_str("o"), v); |
| 1464 v8::Local<v8::Value> res = CompileRun( | 1457 v8::Local<v8::Value> res = CompileRun( |
| 1465 "function f() { return o[0]; }" | 1458 "function f() { return o[0]; }" |
| 1466 "for (var i = 0; i < 10; ++i) f();" | 1459 "for (var i = 0; i < 10; ++i) f();" |
| 1467 "%OptimizeFunctionOnNextCall(f);" | 1460 "%OptimizeFunctionOnNextCall(f);" |
| 1468 "f();"); | 1461 "f();"); |
| 1469 CHECK_EQ(42, res->Int32Value()); | 1462 CHECK_EQ(42, res->Int32Value()); |
| 1470 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0)); | 1463 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0)); |
| 1471 ctx2->Exit(); | 1464 ctx2->Exit(); |
| 1472 ctx1->Exit(); | 1465 ctx1->Exit(); |
| 1473 ctx1.Dispose(); | 1466 ctx1.Dispose(); |
| 1474 v8::V8::ContextDisposedNotification(); | |
| 1475 } | 1467 } |
| 1476 HEAP->CollectAllAvailableGarbage(); | 1468 HEAP->CollectAllAvailableGarbage(); |
| 1477 CHECK_EQ(2, NumberOfGlobalObjects()); | 1469 CHECK_EQ(2, NumberOfGlobalObjects()); |
| 1478 ctx2.Dispose(); | 1470 ctx2.Dispose(); |
| 1479 HEAP->CollectAllAvailableGarbage(); | 1471 HEAP->CollectAllAvailableGarbage(); |
| 1480 CHECK_EQ(0, NumberOfGlobalObjects()); | 1472 CHECK_EQ(0, NumberOfGlobalObjects()); |
| 1481 } | 1473 } |
| 1482 | 1474 |
| 1483 | 1475 |
| 1484 TEST(LeakNativeContextViaMapProto) { | 1476 TEST(LeakGlobalContextViaMapProto) { |
| 1485 i::FLAG_allow_natives_syntax = true; | 1477 i::FLAG_allow_natives_syntax = true; |
| 1486 v8::HandleScope outer_scope; | 1478 v8::HandleScope outer_scope; |
| 1487 v8::Persistent<v8::Context> ctx1 = v8::Context::New(); | 1479 v8::Persistent<v8::Context> ctx1 = v8::Context::New(); |
| 1488 v8::Persistent<v8::Context> ctx2 = v8::Context::New(); | 1480 v8::Persistent<v8::Context> ctx2 = v8::Context::New(); |
| 1489 ctx1->Enter(); | 1481 ctx1->Enter(); |
| 1490 | 1482 |
| 1491 HEAP->CollectAllAvailableGarbage(); | 1483 HEAP->CollectAllAvailableGarbage(); |
| 1492 CHECK_EQ(4, NumberOfGlobalObjects()); | 1484 CHECK_EQ(4, NumberOfGlobalObjects()); |
| 1493 | 1485 |
| 1494 { | 1486 { |
| 1495 v8::HandleScope inner_scope; | 1487 v8::HandleScope inner_scope; |
| 1496 CompileRun("var v = { y: 42}"); | 1488 CompileRun("var v = { y: 42}"); |
| 1497 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v")); | 1489 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v")); |
| 1498 ctx2->Enter(); | 1490 ctx2->Enter(); |
| 1499 ctx2->Global()->Set(v8_str("o"), v); | 1491 ctx2->Global()->Set(v8_str("o"), v); |
| 1500 v8::Local<v8::Value> res = CompileRun( | 1492 v8::Local<v8::Value> res = CompileRun( |
| 1501 "function f() {" | 1493 "function f() {" |
| 1502 " var p = {x: 42};" | 1494 " var p = {x: 42};" |
| 1503 " p.__proto__ = o;" | 1495 " p.__proto__ = o;" |
| 1504 " return p.x;" | 1496 " return p.x;" |
| 1505 "}" | 1497 "}" |
| 1506 "for (var i = 0; i < 10; ++i) f();" | 1498 "for (var i = 0; i < 10; ++i) f();" |
| 1507 "%OptimizeFunctionOnNextCall(f);" | 1499 "%OptimizeFunctionOnNextCall(f);" |
| 1508 "f();"); | 1500 "f();"); |
| 1509 CHECK_EQ(42, res->Int32Value()); | 1501 CHECK_EQ(42, res->Int32Value()); |
| 1510 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0)); | 1502 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0)); |
| 1511 ctx2->Exit(); | 1503 ctx2->Exit(); |
| 1512 ctx1->Exit(); | 1504 ctx1->Exit(); |
| 1513 ctx1.Dispose(); | 1505 ctx1.Dispose(); |
| 1514 v8::V8::ContextDisposedNotification(); | |
| 1515 } | 1506 } |
| 1516 HEAP->CollectAllAvailableGarbage(); | 1507 HEAP->CollectAllAvailableGarbage(); |
| 1517 CHECK_EQ(2, NumberOfGlobalObjects()); | 1508 CHECK_EQ(2, NumberOfGlobalObjects()); |
| 1518 ctx2.Dispose(); | 1509 ctx2.Dispose(); |
| 1519 HEAP->CollectAllAvailableGarbage(); | 1510 HEAP->CollectAllAvailableGarbage(); |
| 1520 CHECK_EQ(0, NumberOfGlobalObjects()); | 1511 CHECK_EQ(0, NumberOfGlobalObjects()); |
| 1521 } | 1512 } |
| 1522 | 1513 |
| 1523 | 1514 |
| 1524 TEST(InstanceOfStubWriteBarrier) { | 1515 TEST(InstanceOfStubWriteBarrier) { |
| (...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2042 fun1 = env->Global()->Get(v8_str("fun")); | 2033 fun1 = env->Global()->Get(v8_str("fun")); |
| 2043 } | 2034 } |
| 2044 | 2035 |
| 2045 { | 2036 { |
| 2046 LocalContext env; | 2037 LocalContext env; |
| 2047 CompileRun("function fun() {};"); | 2038 CompileRun("function fun() {};"); |
| 2048 fun2 = env->Global()->Get(v8_str("fun")); | 2039 fun2 = env->Global()->Get(v8_str("fun")); |
| 2049 } | 2040 } |
| 2050 | 2041 |
| 2051 // Prepare function f that contains type feedback for closures | 2042 // Prepare function f that contains type feedback for closures |
| 2052 // originating from two different native contexts. | 2043 // originating from two different global contexts. |
| 2053 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1); | 2044 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1); |
| 2054 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2); | 2045 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2); |
| 2055 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);"); | 2046 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);"); |
| 2056 Handle<JSFunction> f = | 2047 Handle<JSFunction> f = |
| 2057 v8::Utils::OpenHandle( | 2048 v8::Utils::OpenHandle( |
| 2058 *v8::Handle<v8::Function>::Cast( | 2049 *v8::Handle<v8::Function>::Cast( |
| 2059 v8::Context::GetCurrent()->Global()->Get(v8_str("f")))); | 2050 v8::Context::GetCurrent()->Global()->Get(v8_str("f")))); |
| 2060 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast( | 2051 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast( |
| 2061 f->shared()->code()->type_feedback_info())->type_feedback_cells()); | 2052 f->shared()->code()->type_feedback_info())->type_feedback_cells()); |
| 2062 | 2053 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2088 return NULL; | 2079 return NULL; |
| 2089 } | 2080 } |
| 2090 | 2081 |
| 2091 | 2082 |
| 2092 TEST(IncrementalMarkingPreservesMonomorhpicIC) { | 2083 TEST(IncrementalMarkingPreservesMonomorhpicIC) { |
| 2093 if (i::FLAG_always_opt) return; | 2084 if (i::FLAG_always_opt) return; |
| 2094 InitializeVM(); | 2085 InitializeVM(); |
| 2095 v8::HandleScope scope; | 2086 v8::HandleScope scope; |
| 2096 | 2087 |
| 2097 // Prepare function f that contains a monomorphic IC for object | 2088 // Prepare function f that contains a monomorphic IC for object |
| 2098 // originating from the same native context. | 2089 // originating from the same global context. |
| 2099 CompileRun("function fun() { this.x = 1; }; var obj = new fun();" | 2090 CompileRun("function fun() { this.x = 1; }; var obj = new fun();" |
| 2100 "function f(o) { return o.x; } f(obj); f(obj);"); | 2091 "function f(o) { return o.x; } f(obj); f(obj);"); |
| 2101 Handle<JSFunction> f = | 2092 Handle<JSFunction> f = |
| 2102 v8::Utils::OpenHandle( | 2093 v8::Utils::OpenHandle( |
| 2103 *v8::Handle<v8::Function>::Cast( | 2094 *v8::Handle<v8::Function>::Cast( |
| 2104 v8::Context::GetCurrent()->Global()->Get(v8_str("f")))); | 2095 v8::Context::GetCurrent()->Global()->Get(v8_str("f")))); |
| 2105 | 2096 |
| 2106 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); | 2097 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); |
| 2107 CHECK(ic_before->ic_state() == MONOMORPHIC); | 2098 CHECK(ic_before->ic_state() == MONOMORPHIC); |
| 2108 | 2099 |
| 2100 // Fire context dispose notification. |
| 2101 v8::V8::ContextDisposedNotification(); |
| 2109 SimulateIncrementalMarking(); | 2102 SimulateIncrementalMarking(); |
| 2110 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | 2103 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
| 2111 | 2104 |
| 2112 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); | 2105 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); |
| 2113 CHECK(ic_after->ic_state() == MONOMORPHIC); | 2106 CHECK(ic_after->ic_state() == MONOMORPHIC); |
| 2114 } | 2107 } |
| 2115 | 2108 |
| 2116 | 2109 |
| 2117 TEST(IncrementalMarkingClearsMonomorhpicIC) { | 2110 TEST(IncrementalMarkingClearsMonomorhpicIC) { |
| 2118 if (i::FLAG_always_opt) return; | 2111 if (i::FLAG_always_opt) return; |
| 2119 InitializeVM(); | 2112 InitializeVM(); |
| 2120 v8::HandleScope scope; | 2113 v8::HandleScope scope; |
| 2121 v8::Local<v8::Value> obj1; | 2114 v8::Local<v8::Value> obj1; |
| 2122 | 2115 |
| 2123 { | 2116 { |
| 2124 LocalContext env; | 2117 LocalContext env; |
| 2125 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"); | 2118 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"); |
| 2126 obj1 = env->Global()->Get(v8_str("obj")); | 2119 obj1 = env->Global()->Get(v8_str("obj")); |
| 2127 } | 2120 } |
| 2128 | 2121 |
| 2129 // Prepare function f that contains a monomorphic IC for object | 2122 // Prepare function f that contains a monomorphic IC for object |
| 2130 // originating from a different native context. | 2123 // originating from a different global context. |
| 2131 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1); | 2124 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1); |
| 2132 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);"); | 2125 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);"); |
| 2133 Handle<JSFunction> f = | 2126 Handle<JSFunction> f = |
| 2134 v8::Utils::OpenHandle( | 2127 v8::Utils::OpenHandle( |
| 2135 *v8::Handle<v8::Function>::Cast( | 2128 *v8::Handle<v8::Function>::Cast( |
| 2136 v8::Context::GetCurrent()->Global()->Get(v8_str("f")))); | 2129 v8::Context::GetCurrent()->Global()->Get(v8_str("f")))); |
| 2137 | 2130 |
| 2138 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); | 2131 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); |
| 2139 CHECK(ic_before->ic_state() == MONOMORPHIC); | 2132 CHECK(ic_before->ic_state() == MONOMORPHIC); |
| 2140 | 2133 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2160 obj1 = env->Global()->Get(v8_str("obj")); | 2153 obj1 = env->Global()->Get(v8_str("obj")); |
| 2161 } | 2154 } |
| 2162 | 2155 |
| 2163 { | 2156 { |
| 2164 LocalContext env; | 2157 LocalContext env; |
| 2165 CompileRun("function fun() { this.x = 2; }; var obj = new fun();"); | 2158 CompileRun("function fun() { this.x = 2; }; var obj = new fun();"); |
| 2166 obj2 = env->Global()->Get(v8_str("obj")); | 2159 obj2 = env->Global()->Get(v8_str("obj")); |
| 2167 } | 2160 } |
| 2168 | 2161 |
| 2169 // Prepare function f that contains a polymorphic IC for objects | 2162 // Prepare function f that contains a polymorphic IC for objects |
| 2170 // originating from two different native contexts. | 2163 // originating from two different global contexts. |
| 2171 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1); | 2164 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1); |
| 2172 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2); | 2165 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2); |
| 2173 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);"); | 2166 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);"); |
| 2174 Handle<JSFunction> f = | 2167 Handle<JSFunction> f = |
| 2175 v8::Utils::OpenHandle( | 2168 v8::Utils::OpenHandle( |
| 2176 *v8::Handle<v8::Function>::Cast( | 2169 *v8::Handle<v8::Function>::Cast( |
| 2177 v8::Context::GetCurrent()->Global()->Get(v8_str("f")))); | 2170 v8::Context::GetCurrent()->Global()->Get(v8_str("f")))); |
| 2178 | 2171 |
| 2179 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); | 2172 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); |
| 2180 CHECK(ic_before->ic_state() == MEGAMORPHIC); | 2173 CHECK(ic_before->ic_state() == MEGAMORPHIC); |
| 2181 | 2174 |
| 2182 // Fire context dispose notification. | 2175 // Fire context dispose notification. |
| 2183 v8::V8::ContextDisposedNotification(); | 2176 v8::V8::ContextDisposedNotification(); |
| 2184 SimulateIncrementalMarking(); | 2177 SimulateIncrementalMarking(); |
| 2185 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | 2178 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
| 2186 | 2179 |
| 2187 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); | 2180 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); |
| 2188 CHECK(ic_after->ic_state() == UNINITIALIZED); | 2181 CHECK(ic_after->ic_state() == UNINITIALIZED); |
| 2189 } | 2182 } |
| OLD | NEW |