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:
parent
0cc44c14e5
commit
6503dfb72b
@ -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);
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -36,7 +36,6 @@ namespace {
|
||||
class HarmonyIsolate {
|
||||
public:
|
||||
HarmonyIsolate() {
|
||||
i::FLAG_harmony_observation = true;
|
||||
i::FLAG_harmony_promises = true;
|
||||
isolate_ = Isolate::New();
|
||||
isolate_->Enter();
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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']
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user