Enable Object.observe by default

R=rossberg@chromium.org, rossberg
BUG=v8:2409
LOG=Y

Review URL: https://codereview.chromium.org/183683022

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19734 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
rafaelw@chromium.org 2014-03-08 02:47:53 +00:00
parent eb90940005
commit dcf9842e07
13 changed files with 208 additions and 213 deletions

View File

@ -600,10 +600,7 @@ MaybeObject* Accessors::FunctionSetPrototype(Isolate* isolate,
}
Handle<Object> old_value;
bool is_observed =
FLAG_harmony_observation &&
*function == *object &&
function->map()->is_observed();
bool is_observed = *function == *object && function->map()->is_observed();
if (is_observed) {
if (function->has_prototype())
old_value = handle(function->prototype(), isolate);

View File

@ -1577,6 +1577,12 @@ void Genesis::InstallNativeFunctions() {
INSTALL_NATIVE(JSObject, "functionCache", function_cache);
INSTALL_NATIVE(JSFunction, "ToCompletePropertyDescriptor",
to_complete_property_descriptor);
INSTALL_NATIVE(JSFunction, "NotifyChange", observers_notify_change);
INSTALL_NATIVE(JSFunction, "EnqueueSpliceRecord", observers_enqueue_splice);
INSTALL_NATIVE(JSFunction, "BeginPerformSplice",
observers_begin_perform_splice);
INSTALL_NATIVE(JSFunction, "EndPerformSplice",
observers_end_perform_splice);
}
@ -1591,14 +1597,6 @@ void Genesis::InstallExperimentalNativeFunctions() {
INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap);
INSTALL_NATIVE(JSFunction, "ProxyEnumerate", proxy_enumerate);
}
if (FLAG_harmony_observation) {
INSTALL_NATIVE(JSFunction, "NotifyChange", observers_notify_change);
INSTALL_NATIVE(JSFunction, "EnqueueSpliceRecord", observers_enqueue_splice);
INSTALL_NATIVE(JSFunction, "BeginPerformSplice",
observers_begin_perform_splice);
INSTALL_NATIVE(JSFunction, "EndPerformSplice",
observers_end_perform_splice);
}
}
#undef INSTALL_NATIVE
@ -2042,7 +2040,6 @@ bool Genesis::InstallExperimentalNatives() {
INSTALL_EXPERIMENTAL_NATIVE(i, symbols, "symbol.js")
INSTALL_EXPERIMENTAL_NATIVE(i, proxies, "proxy.js")
INSTALL_EXPERIMENTAL_NATIVE(i, collections, "collection.js")
INSTALL_EXPERIMENTAL_NATIVE(i, observation, "object-observe.js")
INSTALL_EXPERIMENTAL_NATIVE(i, promises, "promise.js")
INSTALL_EXPERIMENTAL_NATIVE(i, generators, "generator.js")
INSTALL_EXPERIMENTAL_NATIVE(i, iteration, "array-iterator.js")

View File

@ -179,8 +179,6 @@ DEFINE_bool(harmony_promises, false, "enable harmony promises")
DEFINE_bool(harmony_proxies, false, "enable harmony proxies")
DEFINE_bool(harmony_collections, false,
"enable harmony collections (sets, maps, and weak maps)")
DEFINE_bool(harmony_observation, false,
"enable harmony object observation (implies harmony collections")
DEFINE_bool(harmony_generators, false, "enable harmony generators")
DEFINE_bool(harmony_iteration, false, "enable harmony iteration (for-of)")
DEFINE_bool(harmony_numeric_literals, false,
@ -196,7 +194,6 @@ DEFINE_implication(harmony, harmony_symbols)
DEFINE_implication(harmony, harmony_promises)
DEFINE_implication(harmony, harmony_proxies)
DEFINE_implication(harmony, harmony_collections)
DEFINE_implication(harmony, harmony_observation)
DEFINE_implication(harmony, harmony_generators)
DEFINE_implication(harmony, harmony_iteration)
DEFINE_implication(harmony, harmony_numeric_literals)
@ -205,7 +202,6 @@ DEFINE_implication(harmony, harmony_arrays)
DEFINE_implication(harmony, harmony_maths)
DEFINE_implication(harmony_promises, harmony_collections)
DEFINE_implication(harmony_modules, harmony_scoping)
DEFINE_implication(harmony_observation, harmony_collections)
// Flags for experimental implementation features.
DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes")

View File

@ -1205,7 +1205,7 @@ MaybeObject* StoreIC::Store(Handle<Object> object,
}
// Observed objects are always modified through the runtime.
if (FLAG_harmony_observation && receiver->map()->is_observed()) {
if (receiver->map()->is_observed()) {
Handle<Object> result = JSReceiver::SetProperty(
receiver, name, value, NONE, strict_mode(), store_mode);
RETURN_IF_EMPTY_HANDLE(isolate(), result);
@ -1671,7 +1671,7 @@ MaybeObject* KeyedStoreIC::Store(Handle<Object> object,
if (maybe_object->IsFailure()) return maybe_object;
} else {
bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() &&
!(FLAG_harmony_observation && object->IsJSObject() &&
!(object->IsJSObject() &&
JSObject::cast(*object)->map()->is_observed());
if (use_ic && !object->IsSmi()) {
// Don't use ICs for maps of the objects in Array's prototype chain. We

View File

@ -56,40 +56,86 @@
// implementation of (1) and (2) have "optimized" states which represent
// common cases which can be handled more efficiently.
var observationState = %GetObservationState();
if (IS_UNDEFINED(observationState.callbackInfoMap)) {
observationState.callbackInfoMap = %ObservationWeakMapCreate();
observationState.objectInfoMap = %ObservationWeakMapCreate();
observationState.notifierObjectInfoMap = %ObservationWeakMapCreate();
observationState.pendingObservers = null;
observationState.nextCallbackPriority = 0;
}
var observationState;
function ObservationWeakMap(map) {
this.map_ = map;
}
function GetObservationState() {
if (IS_UNDEFINED(observationState))
observationState = %GetObservationState();
ObservationWeakMap.prototype = {
get: function(key) {
key = %UnwrapGlobalProxy(key);
if (!IS_SPEC_OBJECT(key)) return UNDEFINED;
return %WeakCollectionGet(this.map_, key);
},
set: function(key, value) {
key = %UnwrapGlobalProxy(key);
if (!IS_SPEC_OBJECT(key)) return UNDEFINED;
%WeakCollectionSet(this.map_, key, value);
},
has: function(key) {
return !IS_UNDEFINED(this.get(key));
if (IS_UNDEFINED(observationState.callbackInfoMap)) {
observationState.callbackInfoMap = %ObservationWeakMapCreate();
observationState.objectInfoMap = %ObservationWeakMapCreate();
observationState.notifierObjectInfoMap = %ObservationWeakMapCreate();
observationState.pendingObservers = null;
observationState.nextCallbackPriority = 0;
}
};
var callbackInfoMap =
new ObservationWeakMap(observationState.callbackInfoMap);
var objectInfoMap = new ObservationWeakMap(observationState.objectInfoMap);
var notifierObjectInfoMap =
new ObservationWeakMap(observationState.notifierObjectInfoMap);
return observationState;
}
function GetWeakMapWrapper() {
function MapWrapper(map) {
this.map_ = map;
};
MapWrapper.prototype = {
get: function(key) {
key = %UnwrapGlobalProxy(key);
if (!IS_SPEC_OBJECT(key)) return UNDEFINED;
return %WeakCollectionGet(this.map_, key);
},
set: function(key, value) {
key = %UnwrapGlobalProxy(key);
if (!IS_SPEC_OBJECT(key)) return UNDEFINED;
%WeakCollectionSet(this.map_, key, value);
},
has: function(key) {
return !IS_UNDEFINED(this.get(key));
}
};
return MapWrapper;
}
var contextMaps;
function GetContextMaps() {
if (IS_UNDEFINED(contextMaps)) {
var map = GetWeakMapWrapper();
var observationState = GetObservationState();
contextMaps = {
callbackInfoMap: new map(observationState.callbackInfoMap),
objectInfoMap: new map(observationState.objectInfoMap),
notifierObjectInfoMap: new map(observationState.notifierObjectInfoMap)
};
}
return contextMaps;
}
function GetCallbackInfoMap() {
return GetContextMaps().callbackInfoMap;
}
function GetObjectInfoMap() {
return GetContextMaps().objectInfoMap;
}
function GetNotifierObjectInfoMap() {
return GetContextMaps().notifierObjectInfoMap;
}
function GetPendingObservers() {
return GetObservationState().pendingObservers;
}
function SetPendingObservers(pendingObservers) {
GetObservationState().pendingObservers = pendingObservers;
}
function GetNextCallbackPriority() {
return GetObservationState().nextCallbackPriority++;
}
function nullProtoObject() {
return { __proto__: null };
@ -180,23 +226,23 @@ function ObjectInfoGetOrCreate(object) {
performing: null,
performingCount: 0,
};
objectInfoMap.set(object, objectInfo);
GetObjectInfoMap().set(object, objectInfo);
}
return objectInfo;
}
function ObjectInfoGet(object) {
return objectInfoMap.get(object);
return GetObjectInfoMap().get(object);
}
function ObjectInfoGetFromNotifier(notifier) {
return notifierObjectInfoMap.get(notifier);
return GetNotifierObjectInfoMap().get(notifier);
}
function ObjectInfoGetNotifier(objectInfo) {
if (IS_NULL(objectInfo.notifier)) {
objectInfo.notifier = { __proto__: notifierPrototype };
notifierObjectInfoMap.set(objectInfo.notifier, objectInfo);
GetNotifierObjectInfoMap().set(objectInfo.notifier, objectInfo);
}
return objectInfo.notifier;
@ -302,16 +348,16 @@ function AcceptArgIsValid(arg) {
// priority. When a change record must be enqueued for the callback, it
// normalizes. When delivery clears any pending change records, it re-optimizes.
function CallbackInfoGet(callback) {
return callbackInfoMap.get(callback);
return GetCallbackInfoMap().get(callback);
}
function CallbackInfoGetOrCreate(callback) {
var callbackInfo = callbackInfoMap.get(callback);
var callbackInfo = GetCallbackInfoMap().get(callback);
if (!IS_UNDEFINED(callbackInfo))
return callbackInfo;
var priority = observationState.nextCallbackPriority++
callbackInfoMap.set(callback, priority);
var priority = GetNextCallbackPriority();
GetCallbackInfoMap().set(callback, priority);
return priority;
}
@ -323,12 +369,12 @@ function CallbackInfoGetPriority(callbackInfo) {
}
function CallbackInfoNormalize(callback) {
var callbackInfo = callbackInfoMap.get(callback);
var callbackInfo = GetCallbackInfoMap().get(callback);
if (IS_NUMBER(callbackInfo)) {
var priority = callbackInfo;
callbackInfo = new InternalArray;
callbackInfo.priority = priority;
callbackInfoMap.set(callback, callbackInfo);
GetCallbackInfoMap().set(callback, callbackInfo);
}
return callbackInfo;
}
@ -390,12 +436,12 @@ function ObserverEnqueueIfActive(observer, objectInfo, changeRecord,
}
var callbackInfo = CallbackInfoNormalize(callback);
if (IS_NULL(observationState.pendingObservers)) {
observationState.pendingObservers = nullProtoObject();
if (IS_NULL(GetPendingObservers())) {
SetPendingObservers(nullProtoObject())
GetMicrotaskQueue().push(ObserveMicrotaskRunner);
%SetMicrotaskPending(true);
}
observationState.pendingObservers[callbackInfo.priority] = callback;
GetPendingObservers()[callbackInfo.priority] = callback;
callbackInfo.push(changeRecord);
}
@ -548,17 +594,17 @@ function ObjectGetNotifier(object) {
}
function CallbackDeliverPending(callback) {
var callbackInfo = callbackInfoMap.get(callback);
var callbackInfo = GetCallbackInfoMap().get(callback);
if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo))
return false;
// Clear the pending change records from callback and return it to its
// "optimized" state.
var priority = callbackInfo.priority;
callbackInfoMap.set(callback, priority);
GetCallbackInfoMap().set(callback, priority);
if (observationState.pendingObservers)
delete observationState.pendingObservers[priority];
if (GetPendingObservers())
delete GetPendingObservers()[priority];
var delivered = [];
%MoveArrayContents(callbackInfo, delivered);
@ -577,9 +623,9 @@ function ObjectDeliverChangeRecords(callback) {
}
function ObserveMicrotaskRunner() {
var pendingObservers = observationState.pendingObservers;
var pendingObservers = GetPendingObservers();
if (pendingObservers) {
observationState.pendingObservers = null;
SetPendingObservers(null);
for (var i in pendingObservers) {
CallbackDeliverPending(pendingObservers[i]);
}

View File

@ -2199,8 +2199,7 @@ Handle<Object> JSObject::AddProperty(Handle<JSObject> object,
AddSlowProperty(object, name, value, attributes);
}
if (FLAG_harmony_observation &&
object->map()->is_observed() &&
if (object->map()->is_observed() &&
*name != isolate->heap()->hidden_string()) {
Handle<Object> old_value = isolate->factory()->the_hole_value();
EnqueueChangeRecord(object, "add", name, old_value);
@ -4090,8 +4089,7 @@ Handle<Object> JSObject::SetPropertyForResult(Handle<JSObject> object,
}
Handle<Object> old_value = isolate->factory()->the_hole_value();
bool is_observed = FLAG_harmony_observation &&
object->map()->is_observed() &&
bool is_observed = object->map()->is_observed() &&
*name != isolate->heap()->hidden_string();
if (is_observed && lookup->IsDataProperty()) {
old_value = Object::GetProperty(object, name);
@ -4213,8 +4211,7 @@ Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
Handle<Object> old_value = isolate->factory()->the_hole_value();
PropertyAttributes old_attributes = ABSENT;
bool is_observed = FLAG_harmony_observation &&
object->map()->is_observed() &&
bool is_observed = object->map()->is_observed() &&
*name != isolate->heap()->hidden_string();
if (is_observed && lookup.IsProperty()) {
if (lookup.IsDataProperty()) old_value =
@ -5196,7 +5193,7 @@ Handle<Object> JSObject::DeleteElement(Handle<JSObject> object,
Handle<Object> old_value;
bool should_enqueue_change_record = false;
if (FLAG_harmony_observation && object->map()->is_observed()) {
if (object->map()->is_observed()) {
should_enqueue_change_record = HasLocalElement(object, index);
if (should_enqueue_change_record) {
old_value = object->GetLocalElementAccessorPair(index) != NULL
@ -5267,8 +5264,7 @@ Handle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
}
Handle<Object> old_value = isolate->factory()->the_hole_value();
bool is_observed = FLAG_harmony_observation &&
object->map()->is_observed() &&
bool is_observed = object->map()->is_observed() &&
*name != isolate->heap()->hidden_string();
if (is_observed && lookup.IsDataProperty()) {
old_value = Object::GetProperty(object, name);
@ -5504,7 +5500,7 @@ Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
object->set_map(*new_map);
ASSERT(!object->map()->is_extensible());
if (FLAG_harmony_observation && object->map()->is_observed()) {
if (object->map()->is_observed()) {
EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
isolate->factory()->the_hole_value());
}
@ -6361,8 +6357,7 @@ void JSObject::DefineAccessor(Handle<JSObject> object,
bool is_element = name->AsArrayIndex(&index);
Handle<Object> old_value = isolate->factory()->the_hole_value();
bool is_observed = FLAG_harmony_observation &&
object->map()->is_observed() &&
bool is_observed = object->map()->is_observed() &&
*name != isolate->heap()->hidden_string();
bool preexists = false;
if (is_observed) {
@ -11422,7 +11417,7 @@ static void EndPerformSplice(Handle<JSArray> object) {
MaybeObject* JSArray::SetElementsLength(Object* len) {
// We should never end in here with a pixel or external array.
ASSERT(AllowsSetElementsLength());
if (!(FLAG_harmony_observation && map()->is_observed()))
if (!map()->is_observed())
return GetElementsAccessor()->SetLength(this, len);
Isolate* isolate = GetIsolate();
@ -12553,7 +12548,7 @@ Handle<Object> JSObject::SetElement(Handle<JSObject> object,
dictionary->set_requires_slow_elements();
}
if (!(FLAG_harmony_observation && object->map()->is_observed())) {
if (!object->map()->is_observed()) {
return object->HasIndexedInterceptor()
? SetElementWithInterceptor(object, index, value, attributes, strict_mode,
check_prototype,
@ -13154,7 +13149,7 @@ bool JSObject::ShouldConvertToFastElements() {
if (IsAccessCheckNeeded()) return false;
// Observed objects may not go to fast mode because they rely on map checks,
// and for fast element accesses we sometimes check element kinds only.
if (FLAG_harmony_observation && map()->is_observed()) return false;
if (map()->is_observed()) return false;
FixedArray* elements = FixedArray::cast(this->elements());
SeededNumberDictionary* dictionary = NULL;

View File

@ -1648,7 +1648,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetPrototype) {
ASSERT(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
if (FLAG_harmony_observation && obj->map()->is_observed()) {
if (obj->map()->is_observed()) {
Handle<Object> old_value(
GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);

View File

@ -2004,8 +2004,14 @@ TEST(PrototypeTransitionClearing) {
Factory* factory = isolate->factory();
v8::HandleScope scope(CcTest::isolate());
CompileRun("var base = {};");
Handle<JSObject> baseObject =
v8::Utils::OpenHandle(
*v8::Handle<v8::Object>::Cast(
CcTest::global()->Get(v8_str("base"))));
int initialTransitions = baseObject->map()->NumberOfProtoTransitions();
CompileRun(
"var base = {};"
"var live = [];"
"for (var i = 0; i < 10; i++) {"
" var object = {};"
@ -2014,25 +2020,22 @@ TEST(PrototypeTransitionClearing) {
" if (i >= 3) live.push(object, prototype);"
"}");
Handle<JSObject> baseObject =
v8::Utils::OpenHandle(
*v8::Handle<v8::Object>::Cast(
CcTest::global()->Get(v8_str("base"))));
// Verify that only dead prototype transitions are cleared.
CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
CHECK_EQ(initialTransitions + 10,
baseObject->map()->NumberOfProtoTransitions());
CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
const int transitions = 10 - 3;
CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
CHECK_EQ(initialTransitions + transitions,
baseObject->map()->NumberOfProtoTransitions());
// Verify that prototype transitions array was compacted.
FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
for (int i = 0; i < transitions; i++) {
for (int i = initialTransitions; i < initialTransitions + transitions; i++) {
int j = Map::kProtoTransitionHeaderSize +
i * Map::kProtoTransitionElementsPerEntry;
CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
CHECK(proto->IsTheHole() || proto->IsJSObject());
CHECK(proto->IsJSObject());
}
// Make sure next prototype is placed on an old-space evacuation candidate.

View File

@ -36,7 +36,6 @@ namespace {
class HarmonyIsolate {
public:
HarmonyIsolate() {
i::FLAG_harmony_observation = true;
i::FLAG_harmony_promises = true;
isolate_ = Isolate::New();
isolate_->Enter();

View File

@ -32,33 +32,10 @@
using namespace v8;
namespace i = v8::internal;
namespace {
// Need to create a new isolate when FLAG_harmony_observation is on.
class HarmonyIsolate {
public:
HarmonyIsolate() {
i::FLAG_harmony_observation = true;
isolate_ = Isolate::New();
isolate_->Enter();
}
~HarmonyIsolate() {
isolate_->Exit();
isolate_->Dispose();
}
Isolate* GetIsolate() const { return isolate_; }
private:
Isolate* isolate_;
};
}
TEST(PerIsolateState) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
LocalContext context1(isolate.GetIsolate());
HandleScope scope(CcTest::isolate());
LocalContext context1(CcTest::isolate());
CompileRun(
"var count = 0;"
"var calls = 0;"
@ -71,29 +48,29 @@ TEST(PerIsolateState) {
"(function() { obj.foo = 'bar'; })");
Handle<Value> notify_fun2;
{
LocalContext context2(isolate.GetIsolate());
context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
LocalContext context2(CcTest::isolate());
context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
obj);
notify_fun2 = CompileRun(
"(function() { obj.foo = 'baz'; })");
}
Handle<Value> notify_fun3;
{
LocalContext context3(isolate.GetIsolate());
context3->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
LocalContext context3(CcTest::isolate());
context3->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
obj);
notify_fun3 = CompileRun(
"(function() { obj.foo = 'bat'; })");
}
{
LocalContext context4(isolate.GetIsolate());
LocalContext context4(CcTest::isolate());
context4->Global()->Set(
String::NewFromUtf8(isolate.GetIsolate(), "observer"), observer);
context4->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "fun1"),
String::NewFromUtf8(CcTest::isolate(), "observer"), observer);
context4->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "fun1"),
notify_fun1);
context4->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "fun2"),
context4->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "fun2"),
notify_fun2);
context4->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "fun3"),
context4->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "fun3"),
notify_fun3);
CompileRun("fun1(); fun2(); fun3(); Object.deliverChangeRecords(observer)");
}
@ -103,9 +80,8 @@ TEST(PerIsolateState) {
TEST(EndOfMicrotaskDelivery) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
LocalContext context(isolate.GetIsolate());
HandleScope scope(CcTest::isolate());
LocalContext context(CcTest::isolate());
CompileRun(
"var obj = {};"
"var count = 0;"
@ -117,9 +93,8 @@ TEST(EndOfMicrotaskDelivery) {
TEST(DeliveryOrdering) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
LocalContext context(isolate.GetIsolate());
HandleScope scope(CcTest::isolate());
LocalContext context(CcTest::isolate());
CompileRun(
"var obj1 = {};"
"var obj2 = {};"
@ -149,9 +124,8 @@ TEST(DeliveryOrdering) {
TEST(DeliveryOrderingReentrant) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
LocalContext context(isolate.GetIsolate());
HandleScope scope(CcTest::isolate());
LocalContext context(CcTest::isolate());
CompileRun(
"var obj = {};"
"var reentered = false;"
@ -181,9 +155,8 @@ TEST(DeliveryOrderingReentrant) {
TEST(DeliveryOrderingDeliverChangeRecords) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
LocalContext context(isolate.GetIsolate());
HandleScope scope(CcTest::isolate());
LocalContext context(CcTest::isolate());
CompileRun(
"var obj = {};"
"var ordering = [];"
@ -206,21 +179,20 @@ TEST(DeliveryOrderingDeliverChangeRecords) {
TEST(ObjectHashTableGrowth) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
HandleScope scope(CcTest::isolate());
// Initializing this context sets up initial hash tables.
LocalContext context(isolate.GetIsolate());
LocalContext context(CcTest::isolate());
Handle<Value> obj = CompileRun("obj = {};");
Handle<Value> observer = CompileRun(
"var ran = false;"
"(function() { ran = true })");
{
// As does initializing this context.
LocalContext context2(isolate.GetIsolate());
context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
LocalContext context2(CcTest::isolate());
context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
obj);
context2->Global()->Set(
String::NewFromUtf8(isolate.GetIsolate(), "observer"), observer);
String::NewFromUtf8(CcTest::isolate(), "observer"), observer);
CompileRun(
"var objArr = [];"
// 100 objects should be enough to make the hash table grow
@ -238,9 +210,8 @@ TEST(ObjectHashTableGrowth) {
TEST(GlobalObjectObservation) {
HarmonyIsolate isolate;
LocalContext context(isolate.GetIsolate());
HandleScope scope(isolate.GetIsolate());
LocalContext context(CcTest::isolate());
HandleScope scope(CcTest::isolate());
Handle<Object> global_proxy = context->Global();
CompileRun(
"var records = [];"
@ -261,7 +232,7 @@ TEST(GlobalObjectObservation) {
// to the old context.
context->DetachGlobal();
{
LocalContext context2(isolate.GetIsolate());
LocalContext context2(CcTest::isolate());
CompileRun(
"var records2 = [];"
"var global = this;"
@ -279,7 +250,7 @@ TEST(GlobalObjectObservation) {
{
// Delegates to Context::New
LocalContext context3(
isolate.GetIsolate(), NULL, Handle<ObjectTemplate>(), global_proxy);
CcTest::isolate(), NULL, Handle<ObjectTemplate>(), global_proxy);
CompileRun(
"var records3 = [];"
"Object.observe(this, function(r) { [].push.apply(records3, r) });"
@ -327,12 +298,11 @@ static void ExpectRecords(v8::Isolate* isolate,
}
#define EXPECT_RECORDS(records, expectations) \
ExpectRecords(isolate.GetIsolate(), records, expectations, \
ExpectRecords(CcTest::isolate(), records, expectations, \
ARRAY_SIZE(expectations))
TEST(APITestBasicMutation) {
HarmonyIsolate isolate;
v8::Isolate* v8_isolate = isolate.GetIsolate();
v8::Isolate* v8_isolate = CcTest::isolate();
HandleScope scope(v8_isolate);
LocalContext context(v8_isolate);
Handle<Object> obj = Handle<Object>::Cast(CompileRun(
@ -379,8 +349,7 @@ TEST(APITestBasicMutation) {
TEST(HiddenPrototypeObservation) {
HarmonyIsolate isolate;
v8::Isolate* v8_isolate = isolate.GetIsolate();
v8::Isolate* v8_isolate = CcTest::isolate();
HandleScope scope(v8_isolate);
LocalContext context(v8_isolate);
Handle<FunctionTemplate> tmpl = FunctionTemplate::New(v8_isolate);
@ -431,15 +400,14 @@ static int NumberOfElements(i::Handle<i::JSWeakMap> map) {
TEST(ObservationWeakMap) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
LocalContext context(isolate.GetIsolate());
HandleScope scope(CcTest::isolate());
LocalContext context(CcTest::isolate());
CompileRun(
"var obj = {};"
"Object.observe(obj, function(){});"
"Object.getNotifier(obj);"
"obj = null;");
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate.GetIsolate());
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(CcTest::isolate());
i::Handle<i::JSObject> observation_state =
i_isolate->factory()->observation_state();
i::Handle<i::JSWeakMap> callbackInfoMap =
@ -528,17 +496,16 @@ static Handle<Object> CreateAccessCheckedObject(
TEST(NamedAccessCheck) {
HarmonyIsolate isolate;
const AccessType types[] = { ACCESS_GET, ACCESS_HAS };
for (size_t i = 0; i < ARRAY_SIZE(types); ++i) {
HandleScope scope(isolate.GetIsolate());
LocalContext context(isolate.GetIsolate());
HandleScope scope(CcTest::isolate());
LocalContext context(CcTest::isolate());
g_access_block_type = types[i];
Handle<Object> instance = CreateAccessCheckedObject(
isolate.GetIsolate(),
CcTest::isolate(),
NamedAccessAllowUnlessBlocked,
IndexedAccessAlwaysAllowed,
String::NewFromUtf8(isolate.GetIsolate(), "foo"));
String::NewFromUtf8(CcTest::isolate(), "foo"));
CompileRun("var records = null;"
"var objNoCheck = {};"
"var observer = function(r) { records = r };"
@ -546,11 +513,11 @@ TEST(NamedAccessCheck) {
"Object.observe(objNoCheck, observer);");
Handle<Value> obj_no_check = CompileRun("objNoCheck");
{
LocalContext context2(isolate.GetIsolate());
context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
LocalContext context2(CcTest::isolate());
context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
instance);
context2->Global()->Set(
String::NewFromUtf8(isolate.GetIsolate(), "objNoCheck"),
String::NewFromUtf8(CcTest::isolate(), "objNoCheck"),
obj_no_check);
CompileRun("var records2 = null;"
"var observer2 = function(r) { records2 = r };"
@ -564,9 +531,9 @@ TEST(NamedAccessCheck) {
const RecordExpectation expected_records2[] = {
{ instance, "add", "foo", Handle<Value>() },
{ instance, "update", "foo",
String::NewFromUtf8(isolate.GetIsolate(), "bar") },
String::NewFromUtf8(CcTest::isolate(), "bar") },
{ instance, "reconfigure", "foo",
Number::New(isolate.GetIsolate(), 5) },
Number::New(CcTest::isolate(), 5) },
{ instance, "add", "bar", Handle<Value>() },
{ obj_no_check, "add", "baz", Handle<Value>() },
};
@ -582,15 +549,14 @@ TEST(NamedAccessCheck) {
TEST(IndexedAccessCheck) {
HarmonyIsolate isolate;
const AccessType types[] = { ACCESS_GET, ACCESS_HAS };
for (size_t i = 0; i < ARRAY_SIZE(types); ++i) {
HandleScope scope(isolate.GetIsolate());
LocalContext context(isolate.GetIsolate());
HandleScope scope(CcTest::isolate());
LocalContext context(CcTest::isolate());
g_access_block_type = types[i];
Handle<Object> instance = CreateAccessCheckedObject(
isolate.GetIsolate(), NamedAccessAlwaysAllowed,
IndexedAccessAllowUnlessBlocked, Number::New(isolate.GetIsolate(), 7));
CcTest::isolate(), NamedAccessAlwaysAllowed,
IndexedAccessAllowUnlessBlocked, Number::New(CcTest::isolate(), 7));
CompileRun("var records = null;"
"var objNoCheck = {};"
"var observer = function(r) { records = r };"
@ -598,11 +564,11 @@ TEST(IndexedAccessCheck) {
"Object.observe(objNoCheck, observer);");
Handle<Value> obj_no_check = CompileRun("objNoCheck");
{
LocalContext context2(isolate.GetIsolate());
context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
LocalContext context2(CcTest::isolate());
context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
instance);
context2->Global()->Set(
String::NewFromUtf8(isolate.GetIsolate(), "objNoCheck"),
String::NewFromUtf8(CcTest::isolate(), "objNoCheck"),
obj_no_check);
CompileRun("var records2 = null;"
"var observer2 = function(r) { records2 = r };"
@ -616,8 +582,8 @@ TEST(IndexedAccessCheck) {
const RecordExpectation expected_records2[] = {
{ instance, "add", "7", Handle<Value>() },
{ instance, "update", "7",
String::NewFromUtf8(isolate.GetIsolate(), "foo") },
{ instance, "reconfigure", "7", Number::New(isolate.GetIsolate(), 5) },
String::NewFromUtf8(CcTest::isolate(), "foo") },
{ instance, "reconfigure", "7", Number::New(CcTest::isolate(), 5) },
{ instance, "add", "8", Handle<Value>() },
{ obj_no_check, "add", "42", Handle<Value>() }
};
@ -633,13 +599,12 @@ TEST(IndexedAccessCheck) {
TEST(SpliceAccessCheck) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
LocalContext context(isolate.GetIsolate());
HandleScope scope(CcTest::isolate());
LocalContext context(CcTest::isolate());
g_access_block_type = ACCESS_GET;
Handle<Object> instance = CreateAccessCheckedObject(
isolate.GetIsolate(), NamedAccessAlwaysAllowed,
IndexedAccessAllowUnlessBlocked, Number::New(isolate.GetIsolate(), 1));
CcTest::isolate(), NamedAccessAlwaysAllowed,
IndexedAccessAllowUnlessBlocked, Number::New(CcTest::isolate(), 1));
CompileRun("var records = null;"
"obj[1] = 'foo';"
"obj.length = 2;"
@ -649,11 +614,11 @@ TEST(SpliceAccessCheck) {
"Array.observe(objNoCheck, observer);");
Handle<Value> obj_no_check = CompileRun("objNoCheck");
{
LocalContext context2(isolate.GetIsolate());
context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
LocalContext context2(CcTest::isolate());
context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
instance);
context2->Global()->Set(
String::NewFromUtf8(isolate.GetIsolate(), "objNoCheck"), obj_no_check);
String::NewFromUtf8(CcTest::isolate(), "objNoCheck"), obj_no_check);
CompileRun("var records2 = null;"
"var observer2 = function(r) { records2 = r };"
"Array.observe(obj, observer2);"
@ -680,11 +645,10 @@ TEST(SpliceAccessCheck) {
TEST(DisallowAllForAccessKeys) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
LocalContext context(isolate.GetIsolate());
HandleScope scope(CcTest::isolate());
LocalContext context(CcTest::isolate());
Handle<Object> instance = CreateAccessCheckedObject(
isolate.GetIsolate(), BlockAccessKeys, IndexedAccessAlwaysAllowed);
CcTest::isolate(), BlockAccessKeys, IndexedAccessAlwaysAllowed);
CompileRun("var records = null;"
"var objNoCheck = {};"
"var observer = function(r) { records = r };"
@ -692,11 +656,11 @@ TEST(DisallowAllForAccessKeys) {
"Object.observe(objNoCheck, observer);");
Handle<Value> obj_no_check = CompileRun("objNoCheck");
{
LocalContext context2(isolate.GetIsolate());
context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
LocalContext context2(CcTest::isolate());
context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
instance);
context2->Global()->Set(
String::NewFromUtf8(isolate.GetIsolate(), "objNoCheck"), obj_no_check);
String::NewFromUtf8(CcTest::isolate(), "objNoCheck"), obj_no_check);
CompileRun("var records2 = null;"
"var observer2 = function(r) { records2 = r };"
"Object.observe(obj, observer2);"
@ -719,24 +683,23 @@ TEST(DisallowAllForAccessKeys) {
TEST(AccessCheckDisallowApiModifications) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
LocalContext context(isolate.GetIsolate());
HandleScope scope(CcTest::isolate());
LocalContext context(CcTest::isolate());
Handle<Object> instance = CreateAccessCheckedObject(
isolate.GetIsolate(), BlockAccessKeys, IndexedAccessAlwaysAllowed);
CcTest::isolate(), BlockAccessKeys, IndexedAccessAlwaysAllowed);
CompileRun("var records = null;"
"var observer = function(r) { records = r };"
"Object.observe(obj, observer);");
{
LocalContext context2(isolate.GetIsolate());
context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
LocalContext context2(CcTest::isolate());
context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
instance);
CompileRun("var records2 = null;"
"var observer2 = function(r) { records2 = r };"
"Object.observe(obj, observer2);");
instance->Set(5, String::NewFromUtf8(isolate.GetIsolate(), "bar"));
instance->Set(String::NewFromUtf8(isolate.GetIsolate(), "foo"),
String::NewFromUtf8(isolate.GetIsolate(), "bar"));
instance->Set(5, String::NewFromUtf8(CcTest::isolate(), "bar"));
instance->Set(String::NewFromUtf8(CcTest::isolate(), "foo"),
String::NewFromUtf8(CcTest::isolate(), "bar"));
CompileRun(""); // trigger delivery
const RecordExpectation expected_records2[] = {
{ instance, "add", "5", Handle<Value>() },
@ -749,18 +712,17 @@ TEST(AccessCheckDisallowApiModifications) {
TEST(HiddenPropertiesLeakage) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
LocalContext context(isolate.GetIsolate());
HandleScope scope(CcTest::isolate());
LocalContext context(CcTest::isolate());
CompileRun("var obj = {};"
"var records = null;"
"var observer = function(r) { records = r };"
"Object.observe(obj, observer);");
Handle<Value> obj =
context->Global()->Get(String::NewFromUtf8(isolate.GetIsolate(), "obj"));
context->Global()->Get(String::NewFromUtf8(CcTest::isolate(), "obj"));
Handle<Object>::Cast(obj)
->SetHiddenValue(String::NewFromUtf8(isolate.GetIsolate(), "foo"),
Null(isolate.GetIsolate()));
->SetHiddenValue(String::NewFromUtf8(CcTest::isolate(), "foo"),
Null(CcTest::isolate()));
CompileRun(""); // trigger delivery
CHECK(CompileRun("records")->IsNull());
}

View File

@ -59,7 +59,7 @@ for (i = 0; i < scripts.length; i++) {
}
// This has to be updated if the number of native scripts change.
assertTrue(named_native_count == 16 || named_native_count == 17);
assertTrue(named_native_count == 17 || named_native_count == 18);
// Only the 'gc' extension is loaded.
assertEquals(1, extension_count);
// This script and mjsunit.js has been loaded. If using d8, d8 loads

View File

@ -1062,6 +1062,7 @@
'../../src/regexp.js',
'../../src/arraybuffer.js',
'../../src/typedarray.js',
'../../src/object-observe.js',
'../../src/macros.py',
],
'experimental_library_files': [
@ -1069,7 +1070,6 @@
'../../src/symbol.js',
'../../src/proxy.js',
'../../src/collection.js',
'../../src/object-observe.js',
'../../src/promise.js',
'../../src/generator.js',
'../../src/array-iterator.js',