| Index: test/cctest/test-api.cc | 
| =================================================================== | 
| --- test/cctest/test-api.cc	(revision 9531) | 
| +++ test/cctest/test-api.cc	(working copy) | 
| @@ -80,6 +80,11 @@ | 
| CHECK_EQ(expected, *ascii); | 
| } | 
|  | 
| +static void ExpectInt32(const char* code, int expected) { | 
| +  Local<Value> result = CompileRun(code); | 
| +  CHECK(result->IsInt32()); | 
| +  CHECK_EQ(expected, result->Int32Value()); | 
| +} | 
|  | 
| static void ExpectBoolean(const char* code, bool expected) { | 
| Local<Value> result = CompileRun(code); | 
| @@ -393,11 +398,11 @@ | 
| CHECK(source->IsExternal()); | 
| CHECK_EQ(resource, | 
| static_cast<TestResource*>(source->GetExternalStringResource())); | 
| -    HEAP->CollectAllGarbage(false); | 
| +    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(0, dispose_count); | 
| } | 
| v8::internal::Isolate::Current()->compilation_cache()->Clear(); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllAvailableGarbage(); | 
| CHECK_EQ(1, dispose_count); | 
| } | 
|  | 
| @@ -415,11 +420,11 @@ | 
| Local<Value> value = script->Run(); | 
| CHECK(value->IsNumber()); | 
| CHECK_EQ(7, value->Int32Value()); | 
| -    HEAP->CollectAllGarbage(false); | 
| +    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(0, dispose_count); | 
| } | 
| i::Isolate::Current()->compilation_cache()->Clear(); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllAvailableGarbage(); | 
| CHECK_EQ(1, dispose_count); | 
| } | 
|  | 
| @@ -441,11 +446,12 @@ | 
| Local<Value> value = script->Run(); | 
| CHECK(value->IsNumber()); | 
| CHECK_EQ(7, value->Int32Value()); | 
| -    HEAP->CollectAllGarbage(false); | 
| +    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(0, dispose_count); | 
| } | 
| i::Isolate::Current()->compilation_cache()->Clear(); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  // TODO(1608): This should use kAbortIncrementalMarking. | 
| +  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); | 
| CHECK_EQ(1, dispose_count); | 
| } | 
|  | 
| @@ -467,11 +473,12 @@ | 
| Local<Value> value = script->Run(); | 
| CHECK(value->IsNumber()); | 
| CHECK_EQ(7, value->Int32Value()); | 
| -    HEAP->CollectAllGarbage(false); | 
| +    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(0, dispose_count); | 
| } | 
| i::Isolate::Current()->compilation_cache()->Clear(); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  // TODO(1608): This should use kAbortIncrementalMarking. | 
| +  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); | 
| CHECK_EQ(1, dispose_count); | 
| } | 
|  | 
| @@ -572,8 +579,8 @@ | 
| i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring); | 
| CHECK(isymbol->IsSymbol()); | 
| } | 
| -  HEAP->CollectAllGarbage(false); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| } | 
|  | 
|  | 
| @@ -590,8 +597,8 @@ | 
| i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring); | 
| CHECK(isymbol->IsSymbol()); | 
| } | 
| -  HEAP->CollectAllGarbage(false); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| } | 
|  | 
|  | 
| @@ -672,11 +679,11 @@ | 
| Local<Value> value = script->Run(); | 
| CHECK(value->IsNumber()); | 
| CHECK_EQ(7, value->Int32Value()); | 
| -    HEAP->CollectAllGarbage(false); | 
| +    HEAP->CollectAllAvailableGarbage(); | 
| CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count); | 
| } | 
| i::Isolate::Current()->compilation_cache()->Clear(); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllAvailableGarbage(); | 
| CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls); | 
| CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count); | 
|  | 
| @@ -693,11 +700,11 @@ | 
| Local<Value> value = script->Run(); | 
| CHECK(value->IsNumber()); | 
| CHECK_EQ(7, value->Int32Value()); | 
| -    HEAP->CollectAllGarbage(false); | 
| +    HEAP->CollectAllAvailableGarbage(); | 
| CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count); | 
| } | 
| i::Isolate::Current()->compilation_cache()->Clear(); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllAvailableGarbage(); | 
| CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls); | 
| CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count); | 
| } | 
| @@ -744,8 +751,8 @@ | 
| CHECK_EQ(68, value->Int32Value()); | 
| } | 
| i::Isolate::Current()->compilation_cache()->Clear(); | 
| -  HEAP->CollectAllGarbage(false); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| } | 
|  | 
|  | 
| @@ -1294,7 +1301,198 @@ | 
| return name; | 
| } | 
|  | 
| +// Helper functions for Interceptor/Accessor interaction tests | 
|  | 
| +Handle<Value> SimpleAccessorGetter(Local<String> name, | 
| +                                   const AccessorInfo& info) { | 
| +  Handle<Object> self = info.This(); | 
| +  return self->Get(String::Concat(v8_str("accessor_"), name)); | 
| +} | 
| + | 
| +void SimpleAccessorSetter(Local<String> name, Local<Value> value, | 
| +                          const AccessorInfo& info) { | 
| +  Handle<Object> self = info.This(); | 
| +  self->Set(String::Concat(v8_str("accessor_"), name), value); | 
| +} | 
| + | 
| +Handle<Value> EmptyInterceptorGetter(Local<String> name, | 
| +                                     const AccessorInfo& info) { | 
| +  return Handle<Value>(); | 
| +} | 
| + | 
| +Handle<Value> EmptyInterceptorSetter(Local<String> name, | 
| +                                     Local<Value> value, | 
| +                                     const AccessorInfo& info) { | 
| +  return Handle<Value>(); | 
| +} | 
| + | 
| +Handle<Value> InterceptorGetter(Local<String> name, | 
| +                                const AccessorInfo& info) { | 
| +  // Intercept names that start with 'interceptor_'. | 
| +  String::AsciiValue ascii(name); | 
| +  char* name_str = *ascii; | 
| +  char prefix[] = "interceptor_"; | 
| +  int i; | 
| +  for (i = 0; name_str[i] && prefix[i]; ++i) { | 
| +    if (name_str[i] != prefix[i]) return Handle<Value>(); | 
| +  } | 
| +  Handle<Object> self = info.This(); | 
| +  return self->GetHiddenValue(v8_str(name_str + i)); | 
| +} | 
| + | 
| +Handle<Value> InterceptorSetter(Local<String> name, | 
| +                                Local<Value> value, | 
| +                                const AccessorInfo& info) { | 
| +  // Intercept accesses that set certain integer values. | 
| +  if (value->IsInt32() && value->Int32Value() < 10000) { | 
| +    Handle<Object> self = info.This(); | 
| +    self->SetHiddenValue(name, value); | 
| +    return value; | 
| +  } | 
| +  return Handle<Value>(); | 
| +} | 
| + | 
| +void AddAccessor(Handle<FunctionTemplate> templ, | 
| +                 Handle<String> name, | 
| +                 v8::AccessorGetter getter, | 
| +                 v8::AccessorSetter setter) { | 
| +  templ->PrototypeTemplate()->SetAccessor(name, getter, setter); | 
| +} | 
| + | 
| +void AddInterceptor(Handle<FunctionTemplate> templ, | 
| +                    v8::NamedPropertyGetter getter, | 
| +                    v8::NamedPropertySetter setter) { | 
| +  templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter); | 
| +} | 
| + | 
| +THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) { | 
| +  v8::HandleScope scope; | 
| +  Handle<FunctionTemplate> parent = FunctionTemplate::New(); | 
| +  Handle<FunctionTemplate> child = FunctionTemplate::New(); | 
| +  child->Inherit(parent); | 
| +  AddAccessor(parent, v8_str("age"), | 
| +              SimpleAccessorGetter, SimpleAccessorSetter); | 
| +  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); | 
| +  LocalContext env; | 
| +  env->Global()->Set(v8_str("Child"), child->GetFunction()); | 
| +  CompileRun("var child = new Child;" | 
| +             "child.age = 10;"); | 
| +  ExpectBoolean("child.hasOwnProperty('age')", false); | 
| +  ExpectInt32("child.age", 10); | 
| +  ExpectInt32("child.accessor_age", 10); | 
| +} | 
| + | 
| +THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) { | 
| +  v8::HandleScope scope; | 
| +  Handle<FunctionTemplate> parent = FunctionTemplate::New(); | 
| +  Handle<FunctionTemplate> child = FunctionTemplate::New(); | 
| +  child->Inherit(parent); | 
| +  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); | 
| +  LocalContext env; | 
| +  env->Global()->Set(v8_str("Child"), child->GetFunction()); | 
| +  CompileRun("var child = new Child;" | 
| +             "var parent = child.__proto__;" | 
| +             "Object.defineProperty(parent, 'age', " | 
| +             "  {get: function(){ return this.accessor_age; }, " | 
| +             "   set: function(v){ this.accessor_age = v; }, " | 
| +             "   enumerable: true, configurable: true});" | 
| +             "child.age = 10;"); | 
| +  ExpectBoolean("child.hasOwnProperty('age')", false); | 
| +  ExpectInt32("child.age", 10); | 
| +  ExpectInt32("child.accessor_age", 10); | 
| +} | 
| + | 
| +THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) { | 
| +  v8::HandleScope scope; | 
| +  Handle<FunctionTemplate> parent = FunctionTemplate::New(); | 
| +  Handle<FunctionTemplate> child = FunctionTemplate::New(); | 
| +  child->Inherit(parent); | 
| +  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); | 
| +  LocalContext env; | 
| +  env->Global()->Set(v8_str("Child"), child->GetFunction()); | 
| +  CompileRun("var child = new Child;" | 
| +             "var parent = child.__proto__;" | 
| +             "parent.name = 'Alice';"); | 
| +  ExpectBoolean("child.hasOwnProperty('name')", false); | 
| +  ExpectString("child.name", "Alice"); | 
| +  CompileRun("child.name = 'Bob';"); | 
| +  ExpectString("child.name", "Bob"); | 
| +  ExpectBoolean("child.hasOwnProperty('name')", true); | 
| +  ExpectString("parent.name", "Alice"); | 
| +} | 
| + | 
| +THREADED_TEST(SwitchFromInterceptorToAccessor) { | 
| +  v8::HandleScope scope; | 
| +  Handle<FunctionTemplate> parent = FunctionTemplate::New(); | 
| +  Handle<FunctionTemplate> child = FunctionTemplate::New(); | 
| +  child->Inherit(parent); | 
| +  AddAccessor(parent, v8_str("age"), | 
| +              SimpleAccessorGetter, SimpleAccessorSetter); | 
| +  AddInterceptor(child, InterceptorGetter, InterceptorSetter); | 
| +  LocalContext env; | 
| +  env->Global()->Set(v8_str("Child"), child->GetFunction()); | 
| +  CompileRun("var child = new Child;" | 
| +             "function setAge(i){ child.age = i; };" | 
| +             "for(var i = 0; i <= 10000; i++) setAge(i);"); | 
| +  // All i < 10000 go to the interceptor. | 
| +  ExpectInt32("child.interceptor_age", 9999); | 
| +  // The last i goes to the accessor. | 
| +  ExpectInt32("child.accessor_age", 10000); | 
| +} | 
| + | 
| +THREADED_TEST(SwitchFromAccessorToInterceptor) { | 
| +  v8::HandleScope scope; | 
| +  Handle<FunctionTemplate> parent = FunctionTemplate::New(); | 
| +  Handle<FunctionTemplate> child = FunctionTemplate::New(); | 
| +  child->Inherit(parent); | 
| +  AddAccessor(parent, v8_str("age"), | 
| +              SimpleAccessorGetter, SimpleAccessorSetter); | 
| +  AddInterceptor(child, InterceptorGetter, InterceptorSetter); | 
| +  LocalContext env; | 
| +  env->Global()->Set(v8_str("Child"), child->GetFunction()); | 
| +  CompileRun("var child = new Child;" | 
| +             "function setAge(i){ child.age = i; };" | 
| +             "for(var i = 20000; i >= 9999; i--) setAge(i);"); | 
| +  // All i >= 10000 go to the accessor. | 
| +  ExpectInt32("child.accessor_age", 10000); | 
| +  // The last i goes to the interceptor. | 
| +  ExpectInt32("child.interceptor_age", 9999); | 
| +} | 
| + | 
| +THREADED_TEST(SwitchFromInterceptorToProperty) { | 
| +  v8::HandleScope scope; | 
| +  Handle<FunctionTemplate> parent = FunctionTemplate::New(); | 
| +  Handle<FunctionTemplate> child = FunctionTemplate::New(); | 
| +  child->Inherit(parent); | 
| +  AddInterceptor(child, InterceptorGetter, InterceptorSetter); | 
| +  LocalContext env; | 
| +  env->Global()->Set(v8_str("Child"), child->GetFunction()); | 
| +  CompileRun("var child = new Child;" | 
| +             "function setAge(i){ child.age = i; };" | 
| +             "for(var i = 0; i <= 10000; i++) setAge(i);"); | 
| +  // All i < 10000 go to the interceptor. | 
| +  ExpectInt32("child.interceptor_age", 9999); | 
| +  // The last i goes to child's own property. | 
| +  ExpectInt32("child.age", 10000); | 
| +} | 
| + | 
| +THREADED_TEST(SwitchFromPropertyToInterceptor) { | 
| +  v8::HandleScope scope; | 
| +  Handle<FunctionTemplate> parent = FunctionTemplate::New(); | 
| +  Handle<FunctionTemplate> child = FunctionTemplate::New(); | 
| +  child->Inherit(parent); | 
| +  AddInterceptor(child, InterceptorGetter, InterceptorSetter); | 
| +  LocalContext env; | 
| +  env->Global()->Set(v8_str("Child"), child->GetFunction()); | 
| +  CompileRun("var child = new Child;" | 
| +             "function setAge(i){ child.age = i; };" | 
| +             "for(var i = 20000; i >= 9999; i--) setAge(i);"); | 
| +  // All i >= 10000 go to child's own property. | 
| +  ExpectInt32("child.age", 10000); | 
| +  // The last i goes to the interceptor. | 
| +  ExpectInt32("child.interceptor_age", 9999); | 
| +} | 
| + | 
| THREADED_TEST(NamedPropertyHandlerGetter) { | 
| echo_named_call_count = 0; | 
| v8::HandleScope scope; | 
| @@ -1666,12 +1864,12 @@ | 
|  | 
| // Check reading and writing aligned pointers. | 
| obj->SetPointerInInternalField(0, aligned); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(aligned, obj->GetPointerFromInternalField(0)); | 
|  | 
| // Check reading and writing unaligned pointers. | 
| obj->SetPointerInInternalField(0, unaligned); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0)); | 
|  | 
| delete[] data; | 
| @@ -1697,19 +1895,19 @@ | 
| CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1)); | 
|  | 
| obj->SetPointerInInternalField(0, aligned); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0))); | 
|  | 
| obj->SetPointerInInternalField(0, unaligned); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0))); | 
|  | 
| obj->SetInternalField(0, v8::External::Wrap(aligned)); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(aligned, obj->GetPointerFromInternalField(0)); | 
|  | 
| obj->SetInternalField(0, v8::External::Wrap(unaligned)); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0)); | 
|  | 
| delete[] data; | 
| @@ -1722,7 +1920,7 @@ | 
|  | 
| // Ensure that the test starts with an fresh heap to test whether the hash | 
| // code is based on the address. | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| Local<v8::Object> obj = v8::Object::New(); | 
| int hash = obj->GetIdentityHash(); | 
| int hash1 = obj->GetIdentityHash(); | 
| @@ -1732,7 +1930,7 @@ | 
| // objects should not be assigned the same hash code. If the test below fails | 
| // the random number generator should be evaluated. | 
| CHECK_NE(hash, hash2); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| int hash3 = v8::Object::New()->GetIdentityHash(); | 
| // Make sure that the identity hash is not based on the initial address of | 
| // the object alone. If the test below fails the random number generator | 
| @@ -1769,7 +1967,7 @@ | 
| v8::Local<v8::String> empty = v8_str(""); | 
| v8::Local<v8::String> prop_name = v8_str("prop_name"); | 
|  | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
|  | 
| // Make sure delete of a non-existent hidden value works | 
| CHECK(obj->DeleteHiddenValue(key)); | 
| @@ -1779,7 +1977,7 @@ | 
| CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002))); | 
| CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); | 
|  | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
|  | 
| // Make sure we do not find the hidden property. | 
| CHECK(!obj->Has(empty)); | 
| @@ -1790,7 +1988,7 @@ | 
| CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); | 
| CHECK_EQ(2003, obj->Get(empty)->Int32Value()); | 
|  | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
|  | 
| // Add another property and delete it afterwards to force the object in | 
| // slow case. | 
| @@ -1801,7 +1999,7 @@ | 
| CHECK(obj->Delete(prop_name)); | 
| CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); | 
|  | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
|  | 
| CHECK(obj->DeleteHiddenValue(key)); | 
| CHECK(obj->GetHiddenValue(key).IsEmpty()); | 
| @@ -1908,19 +2106,30 @@ | 
| } | 
|  | 
|  | 
| -static int NumberOfWeakCalls = 0; | 
| +class WeakCallCounter { | 
| + public: | 
| +  explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { } | 
| +  int id() { return id_; } | 
| +  void increment() { number_of_weak_calls_++; } | 
| +  int NumberOfWeakCalls() { return number_of_weak_calls_; } | 
| + private: | 
| +  int id_; | 
| +  int number_of_weak_calls_; | 
| +}; | 
| + | 
| + | 
| static void WeakPointerCallback(Persistent<Value> handle, void* id) { | 
| -  CHECK_EQ(reinterpret_cast<void*>(1234), id); | 
| -  NumberOfWeakCalls++; | 
| +  WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id); | 
| +  CHECK_EQ(1234, counter->id()); | 
| +  counter->increment(); | 
| handle.Dispose(); | 
| } | 
|  | 
| + | 
| THREADED_TEST(ApiObjectGroups) { | 
| HandleScope scope; | 
| LocalContext env; | 
|  | 
| -  NumberOfWeakCalls = 0; | 
| - | 
| Persistent<Object> g1s1; | 
| Persistent<Object> g1s2; | 
| Persistent<Object> g1c1; | 
| @@ -1928,21 +2137,23 @@ | 
| Persistent<Object> g2s2; | 
| Persistent<Object> g2c1; | 
|  | 
| +  WeakCallCounter counter(1234); | 
| + | 
| { | 
| HandleScope scope; | 
| g1s1 = Persistent<Object>::New(Object::New()); | 
| g1s2 = Persistent<Object>::New(Object::New()); | 
| g1c1 = Persistent<Object>::New(Object::New()); | 
| -    g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| -    g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| -    g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| +    g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
| +    g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
| +    g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
|  | 
| g2s1 = Persistent<Object>::New(Object::New()); | 
| g2s2 = Persistent<Object>::New(Object::New()); | 
| g2c1 = Persistent<Object>::New(Object::New()); | 
| -    g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| -    g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| -    g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| +    g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
| +    g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
| +    g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
| } | 
|  | 
| Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root. | 
| @@ -1961,14 +2172,15 @@ | 
| V8::AddObjectGroup(g2_objects, 2); | 
| V8::AddImplicitReferences(g2s2, g2_children, 1); | 
| } | 
| -  // Do a full GC | 
| -  HEAP->CollectGarbage(i::OLD_POINTER_SPACE); | 
| +  // Do a single full GC. Use kMakeHeapIterableMask to ensure that | 
| +  // incremental garbage collection is stopped. | 
| +  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); | 
|  | 
| // All object should be alive. | 
| -  CHECK_EQ(0, NumberOfWeakCalls); | 
| +  CHECK_EQ(0, counter.NumberOfWeakCalls()); | 
|  | 
| // Weaken the root. | 
| -  root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| +  root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
| // But make children strong roots---all the objects (except for children) | 
| // should be collectable now. | 
| g1c1.ClearWeak(); | 
| @@ -1986,17 +2198,17 @@ | 
| V8::AddImplicitReferences(g2s2, g2_children, 1); | 
| } | 
|  | 
| -  HEAP->CollectGarbage(i::OLD_POINTER_SPACE); | 
| +  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); | 
|  | 
| // All objects should be gone. 5 global handles in total. | 
| -  CHECK_EQ(5, NumberOfWeakCalls); | 
| +  CHECK_EQ(5, counter.NumberOfWeakCalls()); | 
|  | 
| // And now make children weak again and collect them. | 
| -  g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| -  g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| +  g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
| +  g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
|  | 
| -  HEAP->CollectGarbage(i::OLD_POINTER_SPACE); | 
| -  CHECK_EQ(7, NumberOfWeakCalls); | 
| +  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); | 
| +  CHECK_EQ(7, counter.NumberOfWeakCalls()); | 
| } | 
|  | 
|  | 
| @@ -2004,7 +2216,7 @@ | 
| HandleScope scope; | 
| LocalContext env; | 
|  | 
| -  NumberOfWeakCalls = 0; | 
| +  WeakCallCounter counter(1234); | 
|  | 
| Persistent<Object> g1s1; | 
| Persistent<Object> g1s2; | 
| @@ -2017,18 +2229,18 @@ | 
| HandleScope scope; | 
| g1s1 = Persistent<Object>::New(Object::New()); | 
| g1s2 = Persistent<Object>::New(Object::New()); | 
| -    g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| -    g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| +    g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
| +    g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
|  | 
| g2s1 = Persistent<Object>::New(Object::New()); | 
| g2s2 = Persistent<Object>::New(Object::New()); | 
| -    g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| -    g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| +    g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
| +    g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
|  | 
| g3s1 = Persistent<Object>::New(Object::New()); | 
| g3s2 = Persistent<Object>::New(Object::New()); | 
| -    g3s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| -    g3s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| +    g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
| +    g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
| } | 
|  | 
| Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root. | 
| @@ -2050,14 +2262,14 @@ | 
| V8::AddObjectGroup(g3_objects, 2); | 
| V8::AddImplicitReferences(g3s1, g3_children, 1); | 
| } | 
| -  // Do a full GC | 
| -  HEAP->CollectGarbage(i::OLD_POINTER_SPACE); | 
| +  // Do a single full GC | 
| +  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); | 
|  | 
| // All object should be alive. | 
| -  CHECK_EQ(0, NumberOfWeakCalls); | 
| +  CHECK_EQ(0, counter.NumberOfWeakCalls()); | 
|  | 
| // Weaken the root. | 
| -  root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); | 
| +  root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); | 
|  | 
| // Groups are deleted, rebuild groups. | 
| { | 
| @@ -2075,10 +2287,10 @@ | 
| V8::AddImplicitReferences(g3s1, g3_children, 1); | 
| } | 
|  | 
| -  HEAP->CollectGarbage(i::OLD_POINTER_SPACE); | 
| +  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); | 
|  | 
| // All objects should be gone. 7 global handles in total. | 
| -  CHECK_EQ(7, NumberOfWeakCalls); | 
| +  CHECK_EQ(7, counter.NumberOfWeakCalls()); | 
| } | 
|  | 
|  | 
| @@ -4305,6 +4517,47 @@ | 
| } | 
|  | 
|  | 
| +static const char* kEmbeddedExtensionSource = | 
| +    "function Ret54321(){return 54321;}~~@@$" | 
| +    "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS."; | 
| +static const int kEmbeddedExtensionSourceValidLen = 34; | 
| + | 
| + | 
| +THREADED_TEST(ExtensionMissingSourceLength) { | 
| +  v8::HandleScope handle_scope; | 
| +  v8::RegisterExtension(new Extension("srclentest_fail", | 
| +                                      kEmbeddedExtensionSource)); | 
| +  const char* extension_names[] = { "srclentest_fail" }; | 
| +  v8::ExtensionConfiguration extensions(1, extension_names); | 
| +  v8::Handle<Context> context = Context::New(&extensions); | 
| +  CHECK_EQ(0, *context); | 
| +} | 
| + | 
| + | 
| +THREADED_TEST(ExtensionWithSourceLength) { | 
| +  for (int source_len = kEmbeddedExtensionSourceValidLen - 1; | 
| +       source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) { | 
| +    v8::HandleScope handle_scope; | 
| +    i::ScopedVector<char> extension_name(32); | 
| +    i::OS::SNPrintF(extension_name, "ext #%d", source_len); | 
| +    v8::RegisterExtension(new Extension(extension_name.start(), | 
| +                                        kEmbeddedExtensionSource, 0, 0, | 
| +                                        source_len)); | 
| +    const char* extension_names[1] = { extension_name.start() }; | 
| +    v8::ExtensionConfiguration extensions(1, extension_names); | 
| +    v8::Handle<Context> context = Context::New(&extensions); | 
| +    if (source_len == kEmbeddedExtensionSourceValidLen) { | 
| +      Context::Scope lock(context); | 
| +      v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run(); | 
| +      CHECK_EQ(v8::Integer::New(54321), result); | 
| +    } else { | 
| +      // Anything but exactly the right length should fail to compile. | 
| +      CHECK_EQ(0, *context); | 
| +    } | 
| +  } | 
| +} | 
| + | 
| + | 
| static const char* kEvalExtensionSource1 = | 
| "function UseEval1() {" | 
| "  var x = 42;" | 
| @@ -4805,7 +5058,7 @@ | 
|  | 
|  | 
| static void InvokeMarkSweep() { | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| } | 
|  | 
|  | 
| @@ -4898,7 +5151,7 @@ | 
| CHECK_EQ(v8::Integer::New(3), args[2]); | 
| CHECK_EQ(v8::Undefined(), args[3]); | 
| v8::HandleScope scope; | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| return v8::Undefined(); | 
| } | 
|  | 
| @@ -7883,7 +8136,7 @@ | 
| Local<String> name, | 
| const AccessorInfo& info) { | 
| ApiTestFuzzer::Fuzz(); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| return v8::Handle<Value>(); | 
| } | 
|  | 
| @@ -8613,7 +8866,7 @@ | 
| int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data())); | 
| ++(*call_count); | 
| if ((*call_count) % 20 == 0) { | 
| -    HEAP->CollectAllGarbage(true); | 
| +    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| } | 
| return v8::Handle<Value>(); | 
| } | 
| @@ -9964,6 +10217,7 @@ | 
|  | 
|  | 
| static int GetGlobalObjectsCount() { | 
| +  i::Isolate::Current()->heap()->EnsureHeapIsIterable(); | 
| int count = 0; | 
| i::HeapIterator it; | 
| for (i::HeapObject* object = it.next(); object != NULL; object = it.next()) | 
| @@ -9978,9 +10232,8 @@ | 
| // the first garbage collection but some of the maps have already | 
| // been marked at that point.  Therefore some of the maps are not | 
| // collected until the second garbage collection. | 
| -  HEAP->global_context_map(); | 
| -  HEAP->CollectAllGarbage(false); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| +  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); | 
| int count = GetGlobalObjectsCount(); | 
| #ifdef DEBUG | 
| if (count != expected) HEAP->TracePathToGlobal(); | 
| @@ -10049,7 +10302,7 @@ | 
| // weak callback of the first handle would be able to 'reallocate' it. | 
| handle1.MakeWeak(NULL, NewPersistentHandleCallback); | 
| handle2.Dispose(); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| } | 
|  | 
|  | 
| @@ -10057,7 +10310,7 @@ | 
|  | 
| void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) { | 
| to_be_disposed.Dispose(); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| handle.Dispose(); | 
| } | 
|  | 
| @@ -10073,7 +10326,7 @@ | 
| } | 
| handle1.MakeWeak(NULL, DisposeAndForceGcCallback); | 
| to_be_disposed = handle2; | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| } | 
|  | 
| void DisposingCallback(v8::Persistent<v8::Value> handle, void*) { | 
| @@ -10099,7 +10352,7 @@ | 
| } | 
| handle2.MakeWeak(NULL, DisposingCallback); | 
| handle3.MakeWeak(NULL, HandleCreatingCallback); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| } | 
|  | 
|  | 
| @@ -10915,7 +11168,7 @@ | 
| { | 
| v8::Locker lock; | 
| // TODO(lrn): Perhaps create some garbage before collecting. | 
| -        HEAP->CollectAllGarbage(false); | 
| +        HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| gc_count_++; | 
| } | 
| i::OS::Sleep(1); | 
| @@ -11037,7 +11290,7 @@ | 
| while (gc_during_apply_ < kRequiredGCs) { | 
| { | 
| v8::Locker lock; | 
| -        HEAP->CollectAllGarbage(false); | 
| +        HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| gc_count_++; | 
| } | 
| i::OS::Sleep(1); | 
| @@ -11753,13 +12006,15 @@ | 
| i::Handle<i::ExternalPixelArray> pixels = | 
| i::Handle<i::ExternalPixelArray>::cast( | 
| FACTORY->NewExternalArray(kElementCount, | 
| -                                       v8::kExternalPixelArray, | 
| -                                       pixel_data)); | 
| -  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification. | 
| +                                    v8::kExternalPixelArray, | 
| +                                    pixel_data)); | 
| +  // Force GC to trigger verification. | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| for (int i = 0; i < kElementCount; i++) { | 
| pixels->set(i, i % 256); | 
| } | 
| -  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification. | 
| +  // Force GC to trigger verification. | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| for (int i = 0; i < kElementCount; i++) { | 
| CHECK_EQ(i % 256, pixels->get_scalar(i)); | 
| CHECK_EQ(i % 256, pixel_data[i]); | 
| @@ -12235,11 +12490,13 @@ | 
| i::Handle<ExternalArrayClass> array = | 
| i::Handle<ExternalArrayClass>::cast( | 
| FACTORY->NewExternalArray(kElementCount, array_type, array_data)); | 
| -  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification. | 
| +  // Force GC to trigger verification. | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| for (int i = 0; i < kElementCount; i++) { | 
| array->set(i, static_cast<ElementType>(i)); | 
| } | 
| -  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification. | 
| +  // Force GC to trigger verification. | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| for (int i = 0; i < kElementCount; i++) { | 
| CHECK_EQ(static_cast<int64_t>(i), | 
| static_cast<int64_t>(array->get_scalar(i))); | 
| @@ -12357,7 +12614,8 @@ | 
| "  }" | 
| "}" | 
| "sum;"); | 
| -  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification. | 
| +  // Force GC to trigger verification. | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(28, result->Int32Value()); | 
|  | 
| // Make sure out-of-range loads do not throw. | 
| @@ -13337,7 +13595,7 @@ | 
| other_context->Enter(); | 
| CompileRun(source_simple); | 
| other_context->Exit(); | 
| -    HEAP->CollectAllGarbage(false); | 
| +    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| if (GetGlobalObjectsCount() == 1) break; | 
| } | 
| CHECK_GE(2, gc_count); | 
| @@ -13359,7 +13617,7 @@ | 
| other_context->Enter(); | 
| CompileRun(source_eval); | 
| other_context->Exit(); | 
| -    HEAP->CollectAllGarbage(false); | 
| +    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| if (GetGlobalObjectsCount() == 1) break; | 
| } | 
| CHECK_GE(2, gc_count); | 
| @@ -13386,7 +13644,7 @@ | 
| other_context->Enter(); | 
| CompileRun(source_exception); | 
| other_context->Exit(); | 
| -    HEAP->CollectAllGarbage(false); | 
| +    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| if (GetGlobalObjectsCount() == 1) break; | 
| } | 
| CHECK_GE(2, gc_count); | 
| @@ -13604,26 +13862,26 @@ | 
| v8::V8::AddGCEpilogueCallback(EpilogueCallback); | 
| CHECK_EQ(0, prologue_call_count); | 
| CHECK_EQ(0, epilogue_call_count); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(1, prologue_call_count); | 
| CHECK_EQ(1, epilogue_call_count); | 
| v8::V8::AddGCPrologueCallback(PrologueCallbackSecond); | 
| v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(2, prologue_call_count); | 
| CHECK_EQ(2, epilogue_call_count); | 
| CHECK_EQ(1, prologue_call_count_second); | 
| CHECK_EQ(1, epilogue_call_count_second); | 
| v8::V8::RemoveGCPrologueCallback(PrologueCallback); | 
| v8::V8::RemoveGCEpilogueCallback(EpilogueCallback); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(2, prologue_call_count); | 
| CHECK_EQ(2, epilogue_call_count); | 
| CHECK_EQ(2, prologue_call_count_second); | 
| CHECK_EQ(2, epilogue_call_count_second); | 
| v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond); | 
| v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond); | 
| -  HEAP->CollectAllGarbage(false); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| CHECK_EQ(2, prologue_call_count); | 
| CHECK_EQ(2, epilogue_call_count); | 
| CHECK_EQ(2, prologue_call_count_second); | 
| @@ -13840,7 +14098,7 @@ | 
| void FailedAccessCheckCallbackGC(Local<v8::Object> target, | 
| v8::AccessType type, | 
| Local<v8::Value> data) { | 
| -  HEAP->CollectAllGarbage(true); | 
| +  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| } | 
|  | 
|  | 
| @@ -14414,7 +14672,7 @@ | 
| "})()", | 
| "ReferenceError: cell is not defined"); | 
| CompileRun("cell = \"new_second\";"); | 
| -    HEAP->CollectAllGarbage(true); | 
| +    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); | 
| ExpectString("readCell()", "new_second"); | 
| ExpectString("readCell()", "new_second"); | 
| } | 
|  |