static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
JSArray* receiver) {
DisallowHeapAllocation no_gc;
- Isolate* isolate = heap->isolate();
- if (!isolate->IsFastArrayConstructorPrototypeChainIntact()) {
- return false;
- }
-
- // If the array prototype chain is intact (and free of elements), and if the
- // receiver's prototype is the array prototype, then we are done.
- Object* prototype = receiver->map()->prototype();
- if (prototype->IsJSArray() &&
- isolate->is_initial_array_prototype(JSArray::cast(prototype))) {
- return true;
- }
-
- // Slow case.
- PrototypeIterator iter(isolate, receiver);
+ PrototypeIterator iter(heap->isolate(), receiver);
return ArrayPrototypeHasNoElements(heap, &iter);
}
// Adding elements to the array prototype would break code that makes sure
// it has no elements. Handle that elsewhere.
- if (isolate->IsAnyInitialArrayPrototype(array)) {
+ if (array->GetIsolate()->is_initial_array_prototype(*array)) {
return MaybeHandle<FixedArrayBase>();
}
void AssumeInitialMapCantChange(Handle<Map> map) {
Insert(DependentCode::kInitialMapChangedGroup, map);
}
+ void AssumeElementsCantBeAdded(Handle<Map> map) {
+ Insert(DependentCode::kElementsCantBeAddedGroup, map);
+ }
void AssumeFieldType(Handle<Map> map) {
Insert(DependentCode::kFieldTypeGroup, map);
}
// Handling of script id generation is in Factory::NewScript.
set_last_script_id(Smi::FromInt(v8::UnboundScript::kNoScriptId));
- Handle<PropertyCell> cell = factory->NewPropertyCell();
- cell->set_value(Smi::FromInt(1));
- set_array_protector(*cell);
-
set_allocation_sites_scratchpad(
*factory->NewFixedArray(kAllocationSiteScratchpadSize, TENURED));
InitializeAllocationSitesScratchpad();
V(FixedArray, keyed_load_dummy_vector, KeyedLoadDummyVector) \
V(FixedArray, detached_contexts, DetachedContexts) \
V(ArrayList, retained_maps, RetainedMaps) \
- V(WeakHashTable, weak_object_to_code_table, WeakObjectToCodeTable) \
- V(PropertyCell, array_protector, ArrayProtector)
+ V(WeakHashTable, weak_object_to_code_table, WeakObjectToCodeTable)
// Entries in this list are limited to Smis and are not visited during GC.
#define SMI_ROOT_LIST(V) \
void MarkDependsOnEmptyArrayProtoElements() {
// Add map dependency if not already added.
if (depends_on_empty_array_proto_elements_) return;
- info()->dependencies()->AssumePropertyCell(
- isolate()->factory()->array_protector());
+ info()->dependencies()->AssumeElementsCantBeAdded(
+ handle(isolate()->initial_object_prototype()->map()));
+ info()->dependencies()->AssumeElementsCantBeAdded(
+ handle(isolate()->initial_array_prototype()->map()));
depends_on_empty_array_proto_elements_ = true;
}
bool Isolate::IsFastArrayConstructorPrototypeChainIntact() {
- Handle<PropertyCell> no_elements_cell =
- handle(heap()->array_protector(), this);
- bool cell_reports_intact = no_elements_cell->value()->IsSmi() &&
- Smi::cast(no_elements_cell->value())->value() == 1;
-
-#ifdef DEBUG
Map* root_array_map =
get_initial_js_array_map(GetInitialFastElementsKind());
+ DCHECK(root_array_map != NULL);
JSObject* initial_array_proto = JSObject::cast(*initial_array_prototype());
- JSObject* initial_object_proto = JSObject::cast(*initial_object_prototype());
-
- if (root_array_map == NULL || initial_array_proto == initial_object_proto) {
- // We are in the bootstrapping process, and the entire check sequence
- // shouldn't be performed.
- return cell_reports_intact;
- }
// Check that the array prototype hasn't been altered WRT empty elements.
- if (root_array_map->prototype() != initial_array_proto) {
- DCHECK_EQ(false, cell_reports_intact);
- return cell_reports_intact;
- }
-
+ if (root_array_map->prototype() != initial_array_proto) return false;
if (initial_array_proto->elements() != heap()->empty_fixed_array()) {
- DCHECK_EQ(false, cell_reports_intact);
- return cell_reports_intact;
+ return false;
}
// Check that the object prototype hasn't been altered WRT empty elements.
+ JSObject* initial_object_proto = JSObject::cast(*initial_object_prototype());
PrototypeIterator iter(this, initial_array_proto);
if (iter.IsAtEnd() || iter.GetCurrent() != initial_object_proto) {
- DCHECK_EQ(false, cell_reports_intact);
- return cell_reports_intact;
+ return false;
}
if (initial_object_proto->elements() != heap()->empty_fixed_array()) {
- DCHECK_EQ(false, cell_reports_intact);
- return cell_reports_intact;
+ return false;
}
iter.Advance();
- if (!iter.IsAtEnd()) {
- DCHECK_EQ(false, cell_reports_intact);
- return cell_reports_intact;
- }
-
-#endif
-
- return cell_reports_intact;
-}
-
-
-void Isolate::UpdateArrayProtectorOnSetElement(Handle<JSObject> object) {
- Handle<PropertyCell> array_protector = factory()->array_protector();
- if (IsFastArrayConstructorPrototypeChainIntact() &&
- object->map()->is_prototype_map()) {
- Object* context = heap()->native_contexts_list();
- while (!context->IsUndefined()) {
- Context* current_context = Context::cast(context);
- if (current_context->get(Context::INITIAL_OBJECT_PROTOTYPE_INDEX) ==
- *object ||
- current_context->get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ==
- *object) {
- PropertyCell::SetValueWithInvalidation(array_protector,
- handle(Smi::FromInt(0), this));
- break;
- }
- context = current_context->get(Context::NEXT_CONTEXT_LINK);
- }
- }
-}
-
-
-bool Isolate::IsAnyInitialArrayPrototype(Handle<JSArray> array) {
- if (array->map()->is_prototype_map()) {
- Object* context = heap()->native_contexts_list();
- while (!context->IsUndefined()) {
- Context* current_context = Context::cast(context);
- if (current_context->get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ==
- *array) {
- return true;
- }
- context = current_context->get(Context::NEXT_CONTEXT_LINK);
- }
- }
- return false;
+ return iter.IsAtEnd();
}
bool IsFastArrayConstructorPrototypeChainIntact();
- // On intent to set an element in object, make sure that appropriate
- // notifications occur if the set is on the elements of the array or
- // object prototype. Also ensure that changes to prototype chain between
- // Array and Object fire notifications.
- void UpdateArrayProtectorOnSetElement(Handle<JSObject> object);
- void UpdateArrayProtectorOnSetPrototype(Handle<JSObject> object) {
- UpdateArrayProtectorOnSetElement(object);
- }
- void UpdateArrayProtectorOnNormalizeElements(Handle<JSObject> object) {
- UpdateArrayProtectorOnSetElement(object);
- }
-
- // Returns true if array is the initial array prototype in any native context.
- bool IsAnyInitialArrayPrototype(Handle<JSArray> array);
-
CallInterfaceDescriptorData* call_descriptor_data(int index);
void IterateDeferredHandles(ObjectVisitor* visitor);
DCHECK(object->HasFastSmiOrObjectElements() ||
object->HasFastDoubleElements() ||
object->HasFastArgumentsElements());
-
- // Ensure that notifications fire if the array or object prototypes are
- // normalizing.
- isolate->UpdateArrayProtectorOnNormalizeElements(object);
-
// Compute the effective length and allocate a new backing store.
int length = object->IsJSArray()
? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
Handle<SeededNumberDictionary> new_element_dictionary;
if (!object->elements()->IsDictionary()) {
new_element_dictionary = GetNormalizedElementDictionary(object);
- isolate->UpdateArrayProtectorOnNormalizeElements(object);
}
Handle<Symbol> transition_marker;
return "transition";
case kPrototypeCheckGroup:
return "prototype-check";
+ case kElementsCantBeAddedGroup:
+ return "elements-cant-be-added";
case kPropertyCellChangedGroup:
return "property-cell-changed";
case kFieldTypeGroup:
// Nothing to do if prototype is already set.
if (map->prototype() == *value) return value;
- isolate->UpdateArrayProtectorOnSetPrototype(real_receiver);
-
PrototypeOptimizationMode mode =
from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode);
// Array optimizations rely on the prototype lookups of Array objects always
// returning undefined. If there is a store to the initial prototype object,
// make sure all of these optimizations are invalidated.
- isolate->UpdateArrayProtectorOnSetElement(object);
+ if (isolate->is_initial_object_prototype(*object) ||
+ isolate->is_initial_array_prototype(*object)) {
+ object->map()->dependent_code()->DeoptimizeDependentCodeGroup(isolate,
+ DependentCode::kElementsCantBeAddedGroup);
+ }
Handle<FixedArray> backing_store(FixedArray::cast(object->elements()));
if (backing_store->map() ==
return value;
}
-
-// static
-void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
- Handle<Object> new_value) {
- if (cell->value() != *new_value) {
- cell->set_value(*new_value);
- Isolate* isolate = cell->GetIsolate();
- cell->dependent_code()->DeoptimizeDependentCodeGroup(
- isolate, DependentCode::kPropertyCellChangedGroup);
- }
-}
} } // namespace v8::internal
// described by this map changes shape (and transitions to a new map),
// possibly invalidating the assumptions embedded in the code.
kPrototypeCheckGroup,
+ // Group of code that depends on elements not being added to objects with
+ // this map.
+ kElementsCantBeAddedGroup,
// Group of code that depends on global property values in property cells
// not being changed.
kPropertyCellChangedGroup,
static Handle<PropertyCell> InvalidateEntry(Handle<NameDictionary> dictionary,
int entry);
- static void SetValueWithInvalidation(Handle<PropertyCell> cell,
- Handle<Object> new_value);
-
DECLARE_CAST(PropertyCell)
// Dispatched behavior.
}
-static void BreakArrayGuarantees(const char* script) {
- v8::Isolate* isolate1 = v8::Isolate::New();
- isolate1->Enter();
- v8::Persistent<v8::Context> context1;
- {
- v8::HandleScope scope(isolate1);
- context1.Reset(isolate1, Context::New(isolate1));
- }
-
- {
- v8::HandleScope scope(isolate1);
- v8::Local<v8::Context> context =
- v8::Local<v8::Context>::New(isolate1, context1);
- v8::Context::Scope context_scope(context);
- v8::internal::Isolate* i_isolate =
- reinterpret_cast<v8::internal::Isolate*>(isolate1);
- CHECK_EQ(true, i_isolate->IsFastArrayConstructorPrototypeChainIntact());
- // Run something in new isolate.
- CompileRun(script);
- CHECK_EQ(false, i_isolate->IsFastArrayConstructorPrototypeChainIntact());
- }
- isolate1->Exit();
- isolate1->Dispose();
-}
-
-
-TEST(VerifyArrayPrototypeGuarantees) {
- // Break fast array hole handling by element changes.
- BreakArrayGuarantees("[].__proto__[1] = 3;");
- BreakArrayGuarantees("Object.prototype[3] = 'three';");
- BreakArrayGuarantees("Array.prototype.push(1);");
- BreakArrayGuarantees("Array.prototype.unshift(1);");
- // Break fast array hole handling by prototype structure changes.
- BreakArrayGuarantees("[].__proto__.__proto__ = { funny: true };");
- // By sending elements to dictionary mode.
- BreakArrayGuarantees("Object.freeze(Array.prototype);");
- BreakArrayGuarantees("Object.freeze(Object.prototype);");
- BreakArrayGuarantees(
- "Object.defineProperty(Array.prototype, 0, {"
- " get: function() { return 3; }});");
- BreakArrayGuarantees(
- "Object.defineProperty(Object.prototype, 0, {"
- " get: function() { return 3; }});");
-}
-
-
TEST(RunTwoIsolatesOnSingleThread) {
// Run isolate 1.
v8::Isolate* isolate1 = v8::Isolate::New();
// Flags: --allow-natives-syntax
// Flags: --concurrent-recompilation --block-concurrent-recompilation
-// Flags: --nostress-opt
-
-// --nostress-opt is in place because this particular optimization
-// (guaranteeing that the Array prototype chain has no elements) is
-// maintained isolate-wide. Once it's been "broken" by the change
-// to the Object prototype below, future compiles will not use the
-// optimization anymore, and the code will remain optimized despite
-// additional changes to the prototype chain.
if (!%IsConcurrentRecompilationSupported()) {
print("Concurrent recompilation is disabled. Skipping this test.");
+++ /dev/null
-// Copyright 2015 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Flags: --allow-natives-syntax
-
-function f1(a, i) {
- return a[i] + 0.5;
-}
-
-var other_realm = Realm.create();
-var arr = [,0.0,2.5];
-assertEquals(0.5, f1(arr, 1));
-assertEquals(0.5, f1(arr, 1));
-%OptimizeFunctionOnNextCall(f1);
-assertEquals(0.5, f1(arr, 1));
-
-Realm.shared = arr.__proto__;
-
-// The call syntax is useful to make sure the native context is that of the
-// other realm.
-Realm.eval(other_realm, "Array.prototype.push.call(Realm.shared, 1);");
-assertEquals(1.5, f1(arr, 0));