static const int kNullValueRootIndex = 7;
static const int kTrueValueRootIndex = 8;
static const int kFalseValueRootIndex = 9;
- static const int kEmptyStringRootIndex = 131;
+ static const int kEmptyStringRootIndex = 132;
static const int kNodeClassIdOffset = 1 * kApiPointerSize;
static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
SeededNumberDictionary::cast(obj)->set_requires_slow_elements();
set_empty_slow_element_dictionary(SeededNumberDictionary::cast(obj));
+ { MaybeObject* maybe_obj = AllocateSymbol();
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_observed_symbol(Symbol::cast(obj));
+
// Handling of script id generation is in Factory::NewScript.
set_last_script_id(Smi::FromInt(v8::Script::kNoScriptId));
V(Map, external_map, ExternalMap) \
V(Symbol, frozen_symbol, FrozenSymbol) \
V(SeededNumberDictionary, empty_slow_element_dictionary, \
- EmptySlowElementDictionary)
+ EmptySlowElementDictionary) \
+ V(Symbol, observed_symbol, ObservedSymbol)
#define ROOT_LIST(V) \
STRONG_ROOT_LIST(V) \
}
var objectInfo = objectInfoMap.get(object);
- if (IS_UNDEFINED(objectInfo)) objectInfo = CreateObjectInfo(object);
- %SetIsObserved(object, true);
+ if (IS_UNDEFINED(objectInfo)) {
+ objectInfo = CreateObjectInfo(object);
+ %SetIsObserved(object);
+ }
EnsureObserverRemoved(objectInfo, callback);
return object;
EnsureObserverRemoved(objectInfo, callback);
-
- if (objectInfo.changeObservers.length === 0 &&
- objectInfo.inactiveObservers.length === 0) {
- %SetIsObserved(object, false);
- }
-
return object;
}
Handle<Object> old_value(isolate->heap()->the_hole_value(), isolate);
PropertyAttributes old_attributes = ABSENT;
bool is_observed = FLAG_harmony_observation && self->map()->is_observed();
- if (is_observed) {
+ if (is_observed && lookup.IsProperty()) {
if (lookup.IsDataProperty()) old_value = Object::GetProperty(self, name);
old_attributes = lookup.GetAttributes();
}
}
+MUST_USE_RESULT MaybeObject* JSObject::SetObserved(Isolate* isolate) {
+ if (map()->is_observed())
+ return isolate->heap()->undefined_value();
+
+ Heap* heap = isolate->heap();
+
+ if (!HasExternalArrayElements()) {
+ // Go to dictionary mode, so that we don't skip map checks.
+ MaybeObject* maybe = NormalizeElements();
+ if (maybe->IsFailure()) return maybe;
+ ASSERT(!HasFastElements());
+ }
+
+ LookupResult result(isolate);
+ map()->LookupTransition(this, heap->observed_symbol(), &result);
+
+ Map* new_map;
+ if (result.IsTransition()) {
+ new_map = result.GetTransitionTarget();
+ ASSERT(new_map->is_observed());
+ } else if (map()->CanHaveMoreTransitions()) {
+ MaybeObject* maybe_new_map = map()->CopyForObserved();
+ if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+ } else {
+ MaybeObject* maybe_copy = map()->Copy();
+ if (!maybe_copy->To(&new_map)) return maybe_copy;
+ new_map->set_is_observed(true);
+ }
+ set_map(new_map);
+
+ return heap->undefined_value();
+}
+
+
MUST_USE_RESULT MaybeObject* JSObject::DeepCopy(Isolate* isolate) {
StackLimitCheck check(isolate);
if (check.HasOverflowed()) return isolate->StackOverflow();
}
+MaybeObject* Map::CopyForObserved() {
+ ASSERT(!is_observed());
+
+ // In case the map owned its own descriptors, share the descriptors and
+ // transfer ownership to the new map.
+ Map* new_map;
+ MaybeObject* maybe_new_map;
+ if (owns_descriptors()) {
+ maybe_new_map = CopyDropDescriptors();
+ } else {
+ maybe_new_map = Copy();
+ }
+ if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+
+ TransitionArray* transitions;
+ MaybeObject* maybe_transitions = AddTransition(GetHeap()->observed_symbol(),
+ new_map,
+ FULL_TRANSITION);
+ if (!maybe_transitions->To(&transitions)) return maybe_transitions;
+ set_transitions(transitions);
+
+ new_map->set_is_observed(true);
+
+ if (owns_descriptors()) {
+ new_map->InitializeDescriptors(instance_descriptors());
+ set_owns_descriptors(false);
+ }
+
+ new_map->SetBackPointer(this);
+ return new_map;
+}
+
+
MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() {
if (pre_allocated_property_fields() == 0) return CopyDropDescriptors();
// ES5 Object.freeze
MUST_USE_RESULT MaybeObject* Freeze(Isolate* isolate);
+
+ // Called the first time an object is observed with ES7 Object.observe.
+ MUST_USE_RESULT MaybeObject* SetObserved(Isolate* isolate);
+
// Copy object
MUST_USE_RESULT MaybeObject* DeepCopy(Isolate* isolate);
int index,
TransitionFlag flag);
MUST_USE_RESULT MaybeObject* AsElementsKind(ElementsKind kind);
+
MUST_USE_RESULT MaybeObject* CopyAsElementsKind(ElementsKind kind,
TransitionFlag flag);
+ MUST_USE_RESULT MaybeObject* CopyForObserved();
MUST_USE_RESULT MaybeObject* CopyNormalized(PropertyNormalizationMode mode,
NormalizedMapSharingMode sharing);
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetIsObserved) {
SealHandleScope shs(isolate);
- ASSERT(args.length() == 2);
+ ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSReceiver, obj, 0);
- CONVERT_BOOLEAN_ARG_CHECKED(is_observed, 1);
if (obj->IsJSGlobalProxy()) {
Object* proto = obj->GetPrototype();
if (proto->IsNull()) return isolate->heap()->undefined_value();
}
ASSERT(!(obj->map()->is_observed() && obj->IsJSObject() &&
JSObject::cast(obj)->HasFastElements()));
- if (obj->map()->is_observed() != is_observed) {
- if (is_observed && obj->IsJSObject() &&
- !JSObject::cast(obj)->HasExternalArrayElements()) {
- // Go to dictionary mode, so that we don't skip map checks.
- MaybeObject* maybe = JSObject::cast(obj)->NormalizeElements();
- if (maybe->IsFailure()) return maybe;
- ASSERT(!JSObject::cast(obj)->HasFastElements());
- }
- MaybeObject* maybe = obj->map()->Copy();
- Map* map;
- if (!maybe->To(&map)) return maybe;
- map->set_is_observed(is_observed);
- obj->set_map(map);
- }
- return isolate->heap()->undefined_value();
+ ASSERT(obj->IsJSObject());
+ return JSObject::cast(obj)->SetObserved(isolate);
}
\
/* Harmony observe */ \
F(IsObserved, 1, 1) \
- F(SetIsObserved, 2, 1) \
+ F(SetIsObserved, 1, 1) \
F(SetObserverDeliveryPending, 0, 1) \
F(GetObservationState, 0, 1) \
F(ObservationWeakMapCreate, 0, 1) \