Reland "Enable Object.observe by default"

Original Issue: https://codereview.chromium.org/183683022/

TBR=rossberg
BUG=v8:2409
LOG=Y

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19736 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
rafaelw@chromium.org 2014-03-08 04:41:06 +00:00
parent 0cc44c14e5
commit 6503dfb72b
14 changed files with 210 additions and 215 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

@ -63,11 +63,11 @@ FAIL getSortedOwnPropertyNames(decodeURI) should be length,name. Was arguments,c
FAIL getSortedOwnPropertyNames(decodeURIComponent) should be length,name. Was arguments,caller,length,name.
FAIL getSortedOwnPropertyNames(encodeURI) should be length,name. Was arguments,caller,length,name.
FAIL getSortedOwnPropertyNames(encodeURIComponent) should be length,name. Was arguments,caller,length,name.
FAIL getSortedOwnPropertyNames(Object) should be create,defineProperties,defineProperty,freeze,getOwnPropertyDescriptor,getOwnPropertyNames,getPrototypeOf,isExtensible,isFrozen,isSealed,keys,length,name,preventExtensions,prototype,seal,setPrototypeOf. Was arguments,caller,create,defineProperties,defineProperty,freeze,getOwnPropertyDescriptor,getOwnPropertyNames,getPrototypeOf,is,isExtensible,isFrozen,isSealed,keys,length,name,preventExtensions,prototype,seal,setPrototypeOf.
FAIL getSortedOwnPropertyNames(Object) should be create,defineProperties,defineProperty,freeze,getOwnPropertyDescriptor,getOwnPropertyNames,getPrototypeOf,isExtensible,isFrozen,isSealed,keys,length,name,preventExtensions,prototype,seal,setPrototypeOf. Was arguments,caller,create,defineProperties,defineProperty,deliverChangeRecords,freeze,getNotifier,getOwnPropertyDescriptor,getOwnPropertyNames,getPrototypeOf,is,isExtensible,isFrozen,isSealed,keys,length,name,observe,preventExtensions,prototype,seal,setPrototypeOf,unobserve.
PASS getSortedOwnPropertyNames(Object.prototype) is ['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', '__proto__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']
FAIL getSortedOwnPropertyNames(Function) should be length,name,prototype. Was arguments,caller,length,name,prototype.
FAIL getSortedOwnPropertyNames(Function.prototype) should be apply,bind,call,constructor,length,name,toString. Was apply,arguments,bind,call,caller,constructor,length,name,toString.
FAIL getSortedOwnPropertyNames(Array) should be isArray,length,name,prototype. Was arguments,caller,isArray,length,name,prototype.
FAIL getSortedOwnPropertyNames(Array) should be isArray,length,name,prototype. Was arguments,caller,isArray,length,name,observe,prototype,unobserve.
PASS getSortedOwnPropertyNames(Array.prototype) is ['concat', 'constructor', 'every', 'filter', 'forEach', 'indexOf', 'join', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']
FAIL getSortedOwnPropertyNames(String) should be fromCharCode,length,name,prototype. Was arguments,caller,fromCharCode,length,name,prototype.
PASS getSortedOwnPropertyNames(String.prototype) is ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'fixed', 'fontcolor', 'fontsize', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'normalize', 'replace', 'search', 'slice', 'small', 'split', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']

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