Version 3.6.5
New incremental garbage collector.
Removed the hard heap size limit (soft heap size limit is still
700/1400Mbytes by default).
Implemented ES5 generic Array.prototype.toString (Issue 1361).
V8 now allows surrogate pair codes in decodeURIComponent (Issue 1415).
Fixed x64 RegExp start-of-string bug (Issues 1746, 1748).
Fixed propertyIsEnumerable for numeric properties (Issue 1692).
Fixed the MinGW and Windows 2000 builds.
Fixed "Prototype chain is not searched if named property handler does
not set a property" (Issue 1636).
Made the RegExp.prototype object be a RegExp object (Issue 1217).
Disallowed future reserved words as labels in strict mode.
Fixed string split to correctly coerce the separator to a string
(Issue 1711).
API: Added an optional source length field to the Extension
constructor.
API: Added Debug::DisableAgent to match existing Debug::EnableAgent
(Issue 1573).
Added "native" target to Makefile for the benefit of Linux distros.
Fixed: debugger stops stepping outside evaluate (Issue 1639).
More work on ES-Harmony proxies. Still hidden behind a flag.
Bug fixes and performance improvements on all platforms.
Review URL: http://codereview.chromium.org/8139027
git-svn-id: http://v8.googlecode.com/svn/trunk@9534 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/runtime.cc b/src/runtime.cc
index 3ea9304..1f52a22 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -42,6 +42,7 @@
#include "deoptimizer.h"
#include "execution.h"
#include "global-handles.h"
+#include "isolate-inl.h"
#include "jsregexp.h"
#include "json-parser.h"
#include "liveedit.h"
@@ -177,6 +178,7 @@
// Pixel elements cannot be created using an object literal.
ASSERT(!copy->HasExternalArrayElements());
switch (copy->GetElementsKind()) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
FixedArray* elements = FixedArray::cast(copy->elements());
if (elements->map() == heap->fixed_cow_array_map()) {
@@ -189,6 +191,9 @@
} else {
for (int i = 0; i < elements->length(); i++) {
Object* value = elements->get(i);
+ ASSERT(value->IsSmi() ||
+ value->IsTheHole() ||
+ (copy->GetElementsKind() == FAST_ELEMENTS));
if (value->IsJSObject()) {
JSObject* js_object = JSObject::cast(value);
{ MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
@@ -432,16 +437,28 @@
is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
+ bool has_non_smi = false;
if (is_cow) {
-#ifdef DEBUG
// Copy-on-write arrays must be shallow (and simple).
- for (int i = 0; i < content->length(); i++) {
- ASSERT(!content->get(i)->IsFixedArray());
- }
+ if (FLAG_smi_only_arrays) {
+ for (int i = 0; i < content->length(); i++) {
+ Object* current = content->get(i);
+ ASSERT(!current->IsFixedArray());
+ if (!current->IsSmi() && !current->IsTheHole()) {
+ has_non_smi = true;
+ }
+ }
+ } else {
+#if DEBUG
+ for (int i = 0; i < content->length(); i++) {
+ ASSERT(!content->get(i)->IsFixedArray());
+ }
#endif
+ }
} else {
for (int i = 0; i < content->length(); i++) {
- if (content->get(i)->IsFixedArray()) {
+ Object* current = content->get(i);
+ if (current->IsFixedArray()) {
// The value contains the constant_properties of a
// simple object or array literal.
Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
@@ -449,12 +466,25 @@
CreateLiteralBoilerplate(isolate, literals, fa);
if (result.is_null()) return result;
content->set(i, *result);
+ has_non_smi = true;
+ } else {
+ if (!current->IsSmi() && !current->IsTheHole()) {
+ has_non_smi = true;
+ }
}
}
}
// Set the elements.
- Handle<JSArray>::cast(object)->SetContent(*content);
+ Handle<JSArray> js_object(Handle<JSArray>::cast(object));
+ isolate->factory()->SetContent(js_object, content);
+
+ if (FLAG_smi_only_arrays) {
+ if (has_non_smi && js_object->HasFastSmiOnlyElements()) {
+ isolate->factory()->EnsureCanContainNonSmiElements(js_object);
+ }
+ }
+
return object;
}
@@ -685,10 +715,8 @@
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
- // TODO(mstarzinger): Currently we cannot use JSProxy objects as keys
- // because they cannot be cast to JSObject to get an identity hash code.
- CONVERT_ARG_CHECKED(JSObject, key, 1);
- return weakmap->table()->Lookup(*key);
+ CONVERT_ARG_CHECKED(JSReceiver, key, 1);
+ return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
}
@@ -696,10 +724,9 @@
HandleScope scope(isolate);
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
- // TODO(mstarzinger): See Runtime_WeakMapGet above.
- CONVERT_ARG_CHECKED(JSObject, key, 1);
+ CONVERT_ARG_CHECKED(JSReceiver, key, 1);
Handle<Object> value(args[2]);
- Handle<ObjectHashTable> table(weakmap->table());
+ Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
weakmap->set_table(*new_table);
return *value;
@@ -1211,46 +1238,17 @@
LookupResult lookup;
global->Lookup(*name, &lookup);
if (lookup.IsProperty()) {
- // Determine if the property is local by comparing the holder
- // against the global object. The information will be used to
- // avoid throwing re-declaration errors when declaring
- // variables or constants that exist in the prototype chain.
- bool is_local = (*global == lookup.holder());
- // Get the property attributes and determine if the property is
- // read-only.
- PropertyAttributes attributes = global->GetPropertyAttribute(*name);
- bool is_read_only = (attributes & READ_ONLY) != 0;
- if (lookup.type() == INTERCEPTOR) {
- // If the interceptor says the property is there, we
- // just return undefined without overwriting the property.
- // Otherwise, we continue to setting the property.
- if (attributes != ABSENT) {
- // Check if the existing property conflicts with regards to const.
- if (is_local && (is_read_only || is_const_property)) {
- const char* type = (is_read_only) ? "const" : "var";
- return ThrowRedeclarationError(isolate, type, name);
- };
- // The property already exists without conflicting: Go to
- // the next declaration.
- continue;
- }
- // Fall-through and introduce the absent property by using
- // SetProperty.
- } else {
- // For const properties, we treat a callback with this name
- // even in the prototype as a conflicting declaration.
- if (is_const_property && (lookup.type() == CALLBACKS)) {
- return ThrowRedeclarationError(isolate, "const", name);
- }
- // Otherwise, we check for locally conflicting declarations.
- if (is_local && (is_read_only || is_const_property)) {
- const char* type = (is_read_only) ? "const" : "var";
- return ThrowRedeclarationError(isolate, type, name);
- }
- // The property already exists without conflicting: Go to
- // the next declaration.
+ // We found an existing property. Unless it was an interceptor
+ // that claims the property is absent, skip this declaration.
+ if (lookup.type() != INTERCEPTOR) {
continue;
}
+ PropertyAttributes attributes = global->GetPropertyAttribute(*name);
+ if (attributes != ABSENT) {
+ continue;
+ }
+ // Fall-through and introduce the absent property by using
+ // SetProperty.
}
} else {
is_function_declaration = true;
@@ -1267,20 +1265,6 @@
LookupResult lookup;
global->LocalLookup(*name, &lookup);
- // There's a local property that we need to overwrite because
- // we're either declaring a function or there's an interceptor
- // that claims the property is absent.
- //
- // Check for conflicting re-declarations. We cannot have
- // conflicting types in case of intercepted properties because
- // they are absent.
- if (lookup.IsProperty() &&
- (lookup.type() != INTERCEPTOR) &&
- (lookup.IsReadOnly() || is_const_property)) {
- const char* type = (lookup.IsReadOnly()) ? "const" : "var";
- return ThrowRedeclarationError(isolate, type, name);
- }
-
// Compute the property attributes. According to ECMA-262, section
// 13, page 71, the property must be read-only and
// non-deletable. However, neither SpiderMonkey nor KJS creates the
@@ -1335,15 +1319,17 @@
HandleScope scope(isolate);
ASSERT(args.length() == 4);
- CONVERT_ARG_CHECKED(Context, context, 0);
+ // Declarations are always made in a function or global context. In the
+ // case of eval code, the context passed is the context of the caller,
+ // which may be some nested context and not the declaration context.
+ RUNTIME_ASSERT(args[0]->IsContext());
+ Handle<Context> context(Context::cast(args[0])->declaration_context());
+
Handle<String> name(String::cast(args[1]));
PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
Handle<Object> initial_value(args[3], isolate);
- // Declarations are always done in a function or global context.
- context = Handle<Context>(context->declaration_context());
-
int index;
PropertyAttributes attributes;
ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
@@ -1352,9 +1338,7 @@
context->Lookup(name, flags, &index, &attributes, &binding_flags);
if (attributes != ABSENT) {
- // The name was declared before; check for conflicting
- // re-declarations: This is similar to the code in parser.cc in
- // the AstBuildingParser::Declare function.
+ // The name was declared before; check for conflicting re-declarations.
if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
// Functions are not read-only.
ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
@@ -1365,53 +1349,41 @@
// Initialize it if necessary.
if (*initial_value != NULL) {
if (index >= 0) {
- // The variable or constant context slot should always be in
- // the function context or the arguments object.
- if (holder->IsContext()) {
- ASSERT(holder.is_identical_to(context));
- if (((attributes & READ_ONLY) == 0) ||
- context->get(index)->IsTheHole()) {
- context->set(index, *initial_value);
- }
- } else {
- // The holder is an arguments object.
- Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
- Handle<Object> result = SetElement(arguments, index, initial_value,
- kNonStrictMode);
- if (result.is_null()) return Failure::Exception();
+ ASSERT(holder.is_identical_to(context));
+ if (((attributes & READ_ONLY) == 0) ||
+ context->get(index)->IsTheHole()) {
+ context->set(index, *initial_value);
}
} else {
- // Slow case: The property is not in the FixedArray part of the context.
- Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
+ // Slow case: The property is in the context extension object of a
+ // function context or the global object of a global context.
+ Handle<JSObject> object = Handle<JSObject>::cast(holder);
RETURN_IF_EMPTY_HANDLE(
isolate,
- SetProperty(context_ext, name, initial_value,
- mode, kNonStrictMode));
+ SetProperty(object, name, initial_value, mode, kNonStrictMode));
}
}
} else {
// The property is not in the function context. It needs to be
- // "declared" in the function context's extension context, or in the
- // global context.
- Handle<JSObject> context_ext;
+ // "declared" in the function context's extension context or as a
+ // property of the the global object.
+ Handle<JSObject> object;
if (context->has_extension()) {
- // The function context's extension context exists - use it.
- context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
+ object = Handle<JSObject>(JSObject::cast(context->extension()));
} else {
- // The function context's extension context does not exists - allocate
- // it.
- context_ext = isolate->factory()->NewJSObject(
+ // Context extension objects are allocated lazily.
+ ASSERT(context->IsFunctionContext());
+ object = isolate->factory()->NewJSObject(
isolate->context_extension_function());
- // And store it in the extension slot.
- context->set_extension(*context_ext);
+ context->set_extension(*object);
}
- ASSERT(*context_ext != NULL);
+ ASSERT(*object != NULL);
// Declare the property by setting it to the initial value if provided,
// or undefined, and use the correct mode (e.g. READ_ONLY attribute for
// constant declarations).
- ASSERT(!context_ext->HasLocalProperty(*name));
+ ASSERT(!object->HasLocalProperty(*name));
Handle<Object> value(isolate->heap()->undefined_value(), isolate);
if (*initial_value != NULL) value = initial_value;
// Declaring a const context slot is a conflicting declaration if
@@ -1421,15 +1393,15 @@
// SetProperty and no setters are invoked for those since they are
// not real JSObjects.
if (initial_value->IsTheHole() &&
- !context_ext->IsJSContextExtensionObject()) {
+ !object->IsJSContextExtensionObject()) {
LookupResult lookup;
- context_ext->Lookup(*name, &lookup);
+ object->Lookup(*name, &lookup);
if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
return ThrowRedeclarationError(isolate, "const", name);
}
}
RETURN_IF_EMPTY_HANDLE(isolate,
- SetProperty(context_ext, name, value, mode,
+ SetProperty(object, name, value, mode,
kNonStrictMode));
}
@@ -1465,64 +1437,32 @@
// to assign to the property.
// Note that objects can have hidden prototypes, so we need to traverse
// the whole chain of hidden prototypes to do a 'local' lookup.
- JSObject* real_holder = global;
+ Object* object = global;
LookupResult lookup;
- while (true) {
- real_holder->LocalLookup(*name, &lookup);
- if (lookup.IsProperty()) {
- // Determine if this is a redeclaration of something read-only.
- if (lookup.IsReadOnly()) {
- // If we found readonly property on one of hidden prototypes,
- // just shadow it.
- if (real_holder != isolate->context()->global()) break;
- return ThrowRedeclarationError(isolate, "const", name);
- }
-
- // Determine if this is a redeclaration of an intercepted read-only
- // property and figure out if the property exists at all.
- bool found = true;
- PropertyType type = lookup.type();
- if (type == INTERCEPTOR) {
- HandleScope handle_scope(isolate);
- Handle<JSObject> holder(real_holder);
- PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
- real_holder = *holder;
- if (intercepted == ABSENT) {
- // The interceptor claims the property isn't there. We need to
- // make sure to introduce it.
- found = false;
- } else if ((intercepted & READ_ONLY) != 0) {
- // The property is present, but read-only. Since we're trying to
- // overwrite it with a variable declaration we must throw a
- // re-declaration error. However if we found readonly property
- // on one of hidden prototypes, just shadow it.
- if (real_holder != isolate->context()->global()) break;
- return ThrowRedeclarationError(isolate, "const", name);
+ while (object->IsJSObject() &&
+ JSObject::cast(object)->map()->is_hidden_prototype()) {
+ JSObject* raw_holder = JSObject::cast(object);
+ raw_holder->LocalLookup(*name, &lookup);
+ if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
+ HandleScope handle_scope(isolate);
+ Handle<JSObject> holder(raw_holder);
+ PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
+ // Update the raw pointer in case it's changed due to GC.
+ raw_holder = *holder;
+ if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
+ // Found an interceptor that's not read only.
+ if (assign) {
+ return raw_holder->SetProperty(
+ &lookup, *name, args[2], attributes, strict_mode);
+ } else {
+ return isolate->heap()->undefined_value();
}
}
-
- if (found && !assign) {
- // The global property is there and we're not assigning any value
- // to it. Just return.
- return isolate->heap()->undefined_value();
- }
-
- // Assign the value (or undefined) to the property.
- Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
- return real_holder->SetProperty(
- &lookup, *name, value, attributes, strict_mode);
}
-
- Object* proto = real_holder->GetPrototype();
- if (!proto->IsJSObject())
- break;
-
- if (!JSObject::cast(proto)->map()->is_hidden_prototype())
- break;
-
- real_holder = JSObject::cast(proto);
+ object = raw_holder->GetPrototype();
}
+ // Reload global in case the loop above performed a GC.
global = isolate->context()->global();
if (assign) {
return global->SetProperty(*name, args[2], attributes, strict_mode);
@@ -1560,25 +1500,9 @@
attributes);
}
- // Determine if this is a redeclaration of something not
- // read-only. In case the result is hidden behind an interceptor we
- // need to ask it for the property attributes.
if (!lookup.IsReadOnly()) {
- if (lookup.type() != INTERCEPTOR) {
- return ThrowRedeclarationError(isolate, "var", name);
- }
-
- PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
-
- // Throw re-declaration error if the intercepted property is present
- // but not read-only.
- if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
- return ThrowRedeclarationError(isolate, "var", name);
- }
-
// Restore global object from context (in case of GC) and continue
- // with setting the value because the property is either absent or
- // read-only. We also have to do redo the lookup.
+ // with setting the value.
HandleScope handle_scope(isolate);
Handle<GlobalObject> global(isolate->context()->global());
@@ -1595,19 +1519,20 @@
return *value;
}
- // Set the value, but only we're assigning the initial value to a
+ // Set the value, but only if we're assigning the initial value to a
// constant. For now, we determine this by checking if the
// current value is the hole.
- // Strict mode handling not needed (const disallowed in strict mode).
+ // Strict mode handling not needed (const is disallowed in strict mode).
PropertyType type = lookup.type();
if (type == FIELD) {
FixedArray* properties = global->properties();
int index = lookup.GetFieldIndex();
- if (properties->get(index)->IsTheHole()) {
+ if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
properties->set(index, *value);
}
} else if (type == NORMAL) {
- if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
+ if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
+ !lookup.IsReadOnly()) {
global->SetNormalizedProperty(&lookup, *value);
}
} else {
@@ -1627,11 +1552,12 @@
Handle<Object> value(args[0], isolate);
ASSERT(!value->IsTheHole());
- CONVERT_ARG_CHECKED(Context, context, 1);
- Handle<String> name(String::cast(args[2]));
// Initializations are always done in a function or global context.
- context = Handle<Context>(context->declaration_context());
+ RUNTIME_ASSERT(args[1]->IsContext());
+ Handle<Context> context(Context::cast(args[1])->declaration_context());
+
+ Handle<String> name(String::cast(args[2]));
int index;
PropertyAttributes attributes;
@@ -1640,39 +1566,19 @@
Handle<Object> holder =
context->Lookup(name, flags, &index, &attributes, &binding_flags);
- // In most situations, the property introduced by the const
- // declaration should be present in the context extension object.
- // However, because declaration and initialization are separate, the
- // property might have been deleted (if it was introduced by eval)
- // before we reach the initialization point.
- //
- // Example:
- //
- // function f() { eval("delete x; const x;"); }
- //
- // In that case, the initialization behaves like a normal assignment
- // to property 'x'.
if (index >= 0) {
- if (holder->IsContext()) {
- // Property was found in a context. Perform the assignment if we
- // found some non-constant or an uninitialized constant.
- Handle<Context> context = Handle<Context>::cast(holder);
- if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
- context->set(index, *value);
- }
- } else {
- // The holder is an arguments object.
- ASSERT((attributes & READ_ONLY) == 0);
- Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
- RETURN_IF_EMPTY_HANDLE(
- isolate,
- SetElement(arguments, index, value, kNonStrictMode));
+ ASSERT(holder->IsContext());
+ // Property was found in a context. Perform the assignment if we
+ // found some non-constant or an uninitialized constant.
+ Handle<Context> context = Handle<Context>::cast(holder);
+ if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
+ context->set(index, *value);
}
return *value;
}
- // The property could not be found, we introduce it in the global
- // context.
+ // The property could not be found, we introduce it as a property of the
+ // global object.
if (attributes == ABSENT) {
Handle<JSObject> global = Handle<JSObject>(
isolate->context()->global());
@@ -1683,29 +1589,41 @@
return *value;
}
- // The property was present in a context extension object.
- Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
+ // The property was present in some function's context extension object,
+ // as a property on the subject of a with, or as a property of the global
+ // object.
+ //
+ // In most situations, eval-introduced consts should still be present in
+ // the context extension object. However, because declaration and
+ // initialization are separate, the property might have been deleted
+ // before we reach the initialization point.
+ //
+ // Example:
+ //
+ // function f() { eval("delete x; const x;"); }
+ //
+ // In that case, the initialization behaves like a normal assignment.
+ Handle<JSObject> object = Handle<JSObject>::cast(holder);
- if (*context_ext == context->extension()) {
- // This is the property that was introduced by the const
- // declaration. Set it if it hasn't been set before. NOTE: We
- // cannot use GetProperty() to get the current value as it
- // 'unholes' the value.
+ if (*object == context->extension()) {
+ // This is the property that was introduced by the const declaration.
+ // Set it if it hasn't been set before. NOTE: We cannot use
+ // GetProperty() to get the current value as it 'unholes' the value.
LookupResult lookup;
- context_ext->LocalLookupRealNamedProperty(*name, &lookup);
+ object->LocalLookupRealNamedProperty(*name, &lookup);
ASSERT(lookup.IsProperty()); // the property was declared
ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
PropertyType type = lookup.type();
if (type == FIELD) {
- FixedArray* properties = context_ext->properties();
+ FixedArray* properties = object->properties();
int index = lookup.GetFieldIndex();
if (properties->get(index)->IsTheHole()) {
properties->set(index, *value);
}
} else if (type == NORMAL) {
- if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
- context_ext->SetNormalizedProperty(&lookup, *value);
+ if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
+ object->SetNormalizedProperty(&lookup, *value);
}
} else {
// We should not reach here. Any real, named property should be
@@ -1713,13 +1631,13 @@
UNREACHABLE();
}
} else {
- // The property was found in a different context extension object.
- // Set it if it is not a read-only property.
+ // The property was found on some other object. Set it if it is not a
+ // read-only property.
if ((attributes & READ_ONLY) == 0) {
// Strict mode not needed (const disallowed in strict mode).
RETURN_IF_EMPTY_HANDLE(
isolate,
- SetProperty(context_ext, name, value, attributes, kNonStrictMode));
+ SetProperty(object, name, value, attributes, kNonStrictMode));
}
}
@@ -1740,6 +1658,19 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_NonSmiElementStored) {
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(JSObject, object, 0);
+ if (FLAG_smi_only_arrays && object->HasFastSmiOnlyElements()) {
+ MaybeObject* maybe_map = object->GetElementsTransitionMap(FAST_ELEMENTS);
+ Map* map;
+ if (!maybe_map->To<Map>(&map)) return maybe_map;
+ object->set_map(Map::cast(map));
+ }
+ return *object;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
HandleScope scope(isolate);
ASSERT(args.length() == 4);
@@ -1825,7 +1756,7 @@
regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
Smi::FromInt(0),
- SKIP_WRITE_BARRIER);
+ SKIP_WRITE_BARRIER); // It's a Smi.
return regexp;
}
@@ -2239,9 +2170,7 @@
literals->set(JSFunction::kLiteralGlobalContextIndex,
context->global_context());
}
- // It's okay to skip the write barrier here because the literals
- // are guaranteed to be in old space.
- target->set_literals(*literals, SKIP_WRITE_BARRIER);
+ target->set_literals(*literals);
target->set_next_function_link(isolate->heap()->undefined_value());
if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
@@ -2325,7 +2254,8 @@
public:
explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
: array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
- length_(0) {
+ length_(0),
+ has_non_smi_elements_(false) {
// Require a non-zero initial size. Ensures that doubling the size to
// extend the array will work.
ASSERT(initial_capacity > 0);
@@ -2333,7 +2263,8 @@
explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
: array_(backing_store),
- length_(0) {
+ length_(0),
+ has_non_smi_elements_(false) {
// Require a non-zero initial size. Ensures that doubling the size to
// extend the array will work.
ASSERT(backing_store->length() > 0);
@@ -2361,12 +2292,15 @@
}
void Add(Object* value) {
+ ASSERT(!value->IsSmi());
ASSERT(length_ < capacity());
array_->set(length_, value);
length_++;
+ has_non_smi_elements_ = true;
}
void Add(Smi* value) {
+ ASSERT(value->IsSmi());
ASSERT(length_ < capacity());
array_->set(length_, value);
length_++;
@@ -2391,7 +2325,7 @@
}
Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
- target_array->set_elements(*array_);
+ FACTORY->SetContent(target_array, array_);
target_array->set_length(Smi::FromInt(length_));
return target_array;
}
@@ -2399,6 +2333,7 @@
private:
Handle<FixedArray> array_;
int length_;
+ bool has_non_smi_elements_;
};
@@ -2893,7 +2828,7 @@
}
} else {
Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
- if (pattern->IsAsciiRepresentation()) {
+ if (pattern_content.IsAscii()) {
FindStringIndices(isolate,
subject_vector,
pattern_content.ToAsciiVector(),
@@ -3019,7 +2954,7 @@
// Shortcut for simple non-regexp global replacements
if (is_global &&
- regexp->TypeTag() == JSRegExp::ATOM &&
+ regexp_handle->TypeTag() == JSRegExp::ATOM &&
compiled_replacement.simple_hint()) {
if (subject_handle->HasOnlyAsciiChars() &&
replacement_handle->HasOnlyAsciiChars()) {
@@ -3242,6 +3177,9 @@
Address end_of_string = answer->address() + string_size;
isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
+ if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
+ MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
+ }
return *answer;
}
@@ -4001,13 +3939,13 @@
// Slow case.
CONVERT_DOUBLE_ARG_CHECKED(value, 0);
if (isnan(value)) {
- return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
+ return *isolate->factory()->nan_symbol();
}
if (isinf(value)) {
if (value < 0) {
- return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
+ return *isolate->factory()->minus_infinity_symbol();
}
- return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
+ return *isolate->factory()->infinity_symbol();
}
char* str = DoubleToRadixCString(value, radix);
MaybeObject* result =
@@ -4023,13 +3961,13 @@
CONVERT_DOUBLE_ARG_CHECKED(value, 0);
if (isnan(value)) {
- return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
+ return *isolate->factory()->nan_symbol();
}
if (isinf(value)) {
if (value < 0) {
- return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
+ return *isolate->factory()->minus_infinity_symbol();
}
- return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
+ return *isolate->factory()->infinity_symbol();
}
CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2I(f_number);
@@ -4048,13 +3986,13 @@
CONVERT_DOUBLE_ARG_CHECKED(value, 0);
if (isnan(value)) {
- return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
+ return *isolate->factory()->nan_symbol();
}
if (isinf(value)) {
if (value < 0) {
- return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
+ return *isolate->factory()->minus_infinity_symbol();
}
- return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
+ return *isolate->factory()->infinity_symbol();
}
CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2I(f_number);
@@ -4073,13 +4011,13 @@
CONVERT_DOUBLE_ARG_CHECKED(value, 0);
if (isnan(value)) {
- return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
+ return *isolate->factory()->nan_symbol();
}
if (isinf(value)) {
if (value < 0) {
- return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
+ return *isolate->factory()->minus_infinity_symbol();
}
- return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
+ return *isolate->factory()->infinity_symbol();
}
CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2I(f_number);
@@ -4269,7 +4207,7 @@
CONVERT_CHECKED(String, name, args[1]);
CONVERT_CHECKED(Smi, flag_setter, args[2]);
Object* fun = args[3];
- RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
+ RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
CONVERT_CHECKED(Smi, flag_attr, args[4]);
int unchecked = flag_attr->value();
RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
@@ -4437,6 +4375,14 @@
return isolate->Throw(*error);
}
+ if (object->IsJSProxy()) {
+ bool has_pending_exception = false;
+ Handle<Object> name = Execution::ToString(key, &has_pending_exception);
+ if (has_pending_exception) return Failure::Exception();
+ return JSProxy::cast(*object)->SetProperty(
+ String::cast(*name), *value, attr, strict_mode);
+ }
+
// If the object isn't a JavaScript object, we ignore the store.
if (!object->IsJSObject()) return *value;
@@ -4556,7 +4502,7 @@
// Check if the given key is an array index.
uint32_t index;
- if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
+ if (key->ToArrayIndex(&index)) {
// In Firefox/SpiderMonkey, Safari and Opera you can access the
// characters of a string using [] notation. In the case of a
// String object we just need to redirect the deletion to the
@@ -4567,8 +4513,7 @@
return isolate->heap()->true_value();
}
- return JSObject::cast(*receiver)->DeleteElement(
- index, JSReceiver::FORCE_DELETION);
+ return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
}
Handle<String> key_string;
@@ -4730,29 +4675,24 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
NoHandleAllocation na;
ASSERT(args.length() == 2);
+ CONVERT_CHECKED(JSReceiver, receiver, args[0]);
+ CONVERT_CHECKED(String, key, args[1]);
- // Only JS receivers can have properties.
- if (args[0]->IsJSReceiver()) {
- JSReceiver* receiver = JSReceiver::cast(args[0]);
- CONVERT_CHECKED(String, key, args[1]);
- if (receiver->HasProperty(key)) return isolate->heap()->true_value();
- }
- return isolate->heap()->false_value();
+ bool result = receiver->HasProperty(key);
+ if (isolate->has_pending_exception()) return Failure::Exception();
+ return isolate->heap()->ToBoolean(result);
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
NoHandleAllocation na;
ASSERT(args.length() == 2);
+ CONVERT_CHECKED(JSReceiver, receiver, args[0]);
+ CONVERT_CHECKED(Smi, index, args[1]);
- // Only JS objects can have elements.
- if (args[0]->IsJSObject()) {
- JSObject* object = JSObject::cast(args[0]);
- CONVERT_CHECKED(Smi, index_obj, args[1]);
- uint32_t index = index_obj->value();
- if (object->HasElement(index)) return isolate->heap()->true_value();
- }
- return isolate->heap()->false_value();
+ bool result = receiver->HasElement(index->value());
+ if (isolate->has_pending_exception()) return Failure::Exception();
+ return isolate->heap()->ToBoolean(result);
}
@@ -4765,7 +4705,37 @@
uint32_t index;
if (key->AsArrayIndex(&index)) {
- return isolate->heap()->ToBoolean(object->HasElement(index));
+ JSObject::LocalElementType type = object->HasLocalElement(index);
+ switch (type) {
+ case JSObject::UNDEFINED_ELEMENT:
+ case JSObject::STRING_CHARACTER_ELEMENT:
+ return isolate->heap()->false_value();
+ case JSObject::INTERCEPTED_ELEMENT:
+ case JSObject::FAST_ELEMENT:
+ return isolate->heap()->true_value();
+ case JSObject::DICTIONARY_ELEMENT: {
+ if (object->IsJSGlobalProxy()) {
+ Object* proto = object->GetPrototype();
+ if (proto->IsNull()) {
+ return isolate->heap()->false_value();
+ }
+ ASSERT(proto->IsJSGlobalObject());
+ object = JSObject::cast(proto);
+ }
+ FixedArray* elements = FixedArray::cast(object->elements());
+ NumberDictionary* dictionary = NULL;
+ if (elements->map() ==
+ isolate->heap()->non_strict_arguments_elements_map()) {
+ dictionary = NumberDictionary::cast(elements->get(1));
+ } else {
+ dictionary = NumberDictionary::cast(elements);
+ }
+ int entry = dictionary->FindEntry(index);
+ ASSERT(entry != NumberDictionary::kNotFound);
+ PropertyDetails details = dictionary->DetailsAt(entry);
+ return isolate->heap()->ToBoolean(!details.IsDontEnum());
+ }
+ }
}
PropertyAttributes att = object->GetLocalPropertyAttribute(key);
@@ -5579,7 +5549,7 @@
StringType* new_string = StringType::cast(new_object);
Char* write_cursor = reinterpret_cast<Char*>(
- new_string->address() + SeqAsciiString::kHeaderSize);
+ new_string->address() + SeqString::kHeaderSize);
if (comma) *(write_cursor++) = ',';
*(write_cursor++) = '"';
@@ -5667,16 +5637,15 @@
StringType* new_string = StringType::cast(new_object);
ASSERT(isolate->heap()->new_space()->Contains(new_string));
- STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
Char* write_cursor = reinterpret_cast<Char*>(
- new_string->address() + SeqAsciiString::kHeaderSize);
+ new_string->address() + SeqString::kHeaderSize);
if (comma) *(write_cursor++) = ',';
write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
write_cursor,
characters);
int final_length = static_cast<int>(
write_cursor - reinterpret_cast<Char*>(
- new_string->address() + SeqAsciiString::kHeaderSize));
+ new_string->address() + SeqString::kHeaderSize));
isolate->heap()->new_space()->
template ShrinkStringAtAllocationBoundary<StringType>(
new_string, final_length);
@@ -5754,9 +5723,8 @@
StringType* new_string = StringType::cast(new_object);
ASSERT(isolate->heap()->new_space()->Contains(new_string));
- STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
Char* write_cursor = reinterpret_cast<Char*>(
- new_string->address() + SeqAsciiString::kHeaderSize);
+ new_string->address() + SeqString::kHeaderSize);
*(write_cursor++) = '[';
for (int i = 0; i < length; i++) {
if (i != 0) *(write_cursor++) = ',';
@@ -5777,7 +5745,7 @@
int final_length = static_cast<int>(
write_cursor - reinterpret_cast<Char*>(
- new_string->address() + SeqAsciiString::kHeaderSize));
+ new_string->address() + SeqString::kHeaderSize));
isolate->heap()->new_space()->
template ShrinkStringAtAllocationBoundary<StringType>(
new_string, final_length);
@@ -6229,6 +6197,8 @@
int part_count = indices.length();
Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
+ MaybeObject* maybe_result = result->EnsureCanContainNonSmiElements();
+ if (maybe_result->IsFailure()) return maybe_result;
result->set_length(Smi::FromInt(part_count));
ASSERT(result->HasFastElements());
@@ -6275,11 +6245,11 @@
FixedArray* ascii_cache = heap->single_character_string_cache();
Object* undefined = heap->undefined_value();
int i;
+ WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
for (i = 0; i < length; ++i) {
Object* value = ascii_cache->get(chars[i]);
if (value == undefined) break;
- ASSERT(!heap->InNewSpace(value));
- elements->set(i, value, SKIP_WRITE_BARRIER);
+ elements->set(i, value, mode);
}
if (i < length) {
ASSERT(Smi::FromInt(0) == 0);
@@ -6603,6 +6573,9 @@
// This assumption is used by the slice encoding in one or two smis.
ASSERT(Smi::kMaxValue >= String::kMaxLength);
+ MaybeObject* maybe_result = array->EnsureCanContainNonSmiElements();
+ if (maybe_result->IsFailure()) return maybe_result;
+
int special_length = special->length();
if (!array->HasFastElements()) {
return isolate->Throw(isolate->heap()->illegal_argument_symbol());
@@ -6830,7 +6803,8 @@
NoHandleAllocation ha;
ASSERT(args.length() == 3);
CONVERT_CHECKED(JSArray, elements_array, args[0]);
- RUNTIME_ASSERT(elements_array->HasFastElements());
+ RUNTIME_ASSERT(elements_array->HasFastElements() ||
+ elements_array->HasFastSmiOnlyElements());
CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
CONVERT_CHECKED(String, separator, args[2]);
// elements_array is fast-mode JSarray of alternating positions
@@ -7997,7 +7971,7 @@
int bound_argc = 0;
if (!args[1]->IsNull()) {
CONVERT_ARG_CHECKED(JSArray, params, 1);
- RUNTIME_ASSERT(params->HasFastElements());
+ RUNTIME_ASSERT(params->HasFastTypeElements());
bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
bound_argc = Smi::cast(params->length())->value();
}
@@ -8307,6 +8281,8 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
+ // The least significant bit (after untagging) indicates whether the
+ // function is currently optimized, regardless of reason.
if (!V8::UseCrankshaft()) {
return Smi::FromInt(4); // 4 == "never".
}
@@ -8479,7 +8455,7 @@
argv[i] = Handle<Object>(object);
}
- bool threw = false;
+ bool threw;
Handle<JSReceiver> hfun(fun);
Handle<Object> hreceiver(receiver);
Handle<Object> result = Execution::Call(
@@ -8646,18 +8622,10 @@
}
// The slot was found in a JSObject, either a context extension object,
- // the global object, or an arguments object. Try to delete it
- // (respecting DONT_DELETE). For consistency with V8's usual behavior,
- // which allows deleting all parameters in functions that mention
- // 'arguments', we do this even for the case of slots found on an
- // arguments object. The slot was found on an arguments object if the
- // index is non-negative.
+ // the global object, or the subject of a with. Try to delete it
+ // (respecting DONT_DELETE).
Handle<JSObject> object = Handle<JSObject>::cast(holder);
- if (index >= 0) {
- return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
- } else {
- return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
- }
+ return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
}
@@ -8742,24 +8710,19 @@
&attributes,
&binding_flags);
- // If the index is non-negative, the slot has been found in a local
- // variable or a parameter. Read it from the context object or the
- // arguments object.
+ // If the index is non-negative, the slot has been found in a context.
if (index >= 0) {
- // If the "property" we were looking for is a local variable or an
- // argument in a context, the receiver is the global object; see
- // ECMA-262, 3rd., 10.1.6 and 10.2.3.
+ ASSERT(holder->IsContext());
+ // If the "property" we were looking for is a local variable, the
+ // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
//
- // Use the hole as the receiver to signal that the receiver is
- // implicit and that the global receiver should be used.
+ // Use the hole as the receiver to signal that the receiver is implicit
+ // and that the global receiver should be used (as distinguished from an
+ // explicit receiver that happens to be a global object).
Handle<Object> receiver = isolate->factory()->the_hole_value();
- MaybeObject* value = (holder->IsContext())
- ? Context::cast(*holder)->get(index)
- : JSObject::cast(*holder)->GetElement(index);
+ Object* value = Context::cast(*holder)->get(index);
// Check for uninitialized bindings.
- if (holder->IsContext() &&
- binding_flags == MUTABLE_CHECK_INITIALIZED &&
- value->IsTheHole()) {
+ if (binding_flags == MUTABLE_CHECK_INITIALIZED && value->IsTheHole()) {
Handle<Object> reference_error =
isolate->factory()->NewReferenceError("not_defined",
HandleVector(&name, 1));
@@ -8769,25 +8732,18 @@
}
}
- // If the holder is found, we read the property from it.
- if (!holder.is_null() && holder->IsJSObject()) {
- ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
- JSObject* object = JSObject::cast(*holder);
- Object* receiver;
- if (object->IsGlobalObject()) {
- receiver = GlobalObject::cast(object)->global_receiver();
- } else if (context->is_exception_holder(*holder)) {
- // Use the hole as the receiver to signal that the receiver is
- // implicit and that the global receiver should be used.
- receiver = isolate->heap()->the_hole_value();
- } else {
- receiver = ComputeReceiverForNonGlobal(isolate, object);
- }
-
+ // Otherwise, if the slot was found the holder is a context extension
+ // object, subject of a with, or a global object. We read the named
+ // property from it.
+ if (!holder.is_null()) {
+ Handle<JSObject> object = Handle<JSObject>::cast(holder);
+ ASSERT(object->HasProperty(*name));
// GetProperty below can cause GC.
- Handle<Object> receiver_handle(receiver);
+ Handle<Object> receiver_handle(object->IsGlobalObject()
+ ? GlobalObject::cast(*object)->global_receiver()
+ : ComputeReceiverForNonGlobal(isolate, *object));
- // No need to unhole the value here. This is taken care of by the
+ // No need to unhole the value here. This is taken care of by the
// GetProperty function.
MaybeObject* value = object->GetProperty(*name);
return MakePair(value, *receiver_handle);
@@ -8840,45 +8796,37 @@
&binding_flags);
if (index >= 0) {
- if (holder->IsContext()) {
- Handle<Context> context = Handle<Context>::cast(holder);
- if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
- context->get(index)->IsTheHole()) {
- Handle<Object> error =
- isolate->factory()->NewReferenceError("not_defined",
- HandleVector(&name, 1));
- return isolate->Throw(*error);
- }
- // Ignore if read_only variable.
- if ((attributes & READ_ONLY) == 0) {
- // Context is a fixed array and set cannot fail.
- context->set(index, *value);
- } else if (strict_mode == kStrictMode) {
- // Setting read only property in strict mode.
- Handle<Object> error =
- isolate->factory()->NewTypeError("strict_cannot_assign",
- HandleVector(&name, 1));
- return isolate->Throw(*error);
- }
- } else {
- ASSERT((attributes & READ_ONLY) == 0);
- Handle<Object> result =
- SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
- if (result.is_null()) {
- ASSERT(isolate->has_pending_exception());
- return Failure::Exception();
- }
+ // The property was found in a context slot.
+ Handle<Context> context = Handle<Context>::cast(holder);
+ if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
+ context->get(index)->IsTheHole()) {
+ Handle<Object> error =
+ isolate->factory()->NewReferenceError("not_defined",
+ HandleVector(&name, 1));
+ return isolate->Throw(*error);
+ }
+ // Ignore if read_only variable.
+ if ((attributes & READ_ONLY) == 0) {
+ // Context is a fixed array and set cannot fail.
+ context->set(index, *value);
+ } else if (strict_mode == kStrictMode) {
+ // Setting read only property in strict mode.
+ Handle<Object> error =
+ isolate->factory()->NewTypeError("strict_cannot_assign",
+ HandleVector(&name, 1));
+ return isolate->Throw(*error);
}
return *value;
}
- // Slow case: The property is not in a FixedArray context.
- // It is either in an JSObject extension context or it was not found.
- Handle<JSObject> context_ext;
+ // Slow case: The property is not in a context slot. It is either in a
+ // context extension object, a property of the subject of a with, or a
+ // property of the global object.
+ Handle<JSObject> object;
if (!holder.is_null()) {
- // The property exists in the extension context.
- context_ext = Handle<JSObject>::cast(holder);
+ // The property exists on the holder.
+ object = Handle<JSObject>::cast(holder);
} else {
// The property was not found.
ASSERT(attributes == ABSENT);
@@ -8886,22 +8834,21 @@
if (strict_mode == kStrictMode) {
// Throw in strict mode (assignment to undefined variable).
Handle<Object> error =
- isolate->factory()->NewReferenceError(
- "not_defined", HandleVector(&name, 1));
+ isolate->factory()->NewReferenceError(
+ "not_defined", HandleVector(&name, 1));
return isolate->Throw(*error);
}
- // In non-strict mode, the property is stored in the global context.
+ // In non-strict mode, the property is added to the global object.
attributes = NONE;
- context_ext = Handle<JSObject>(isolate->context()->global());
+ object = Handle<JSObject>(isolate->context()->global());
}
- // Set the property, but ignore if read_only variable on the context
- // extension object itself.
+ // Set the property if it's not read only or doesn't yet exist.
if ((attributes & READ_ONLY) == 0 ||
- (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
+ (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
RETURN_IF_EMPTY_HANDLE(
isolate,
- SetProperty(context_ext, name, value, NONE, strict_mode));
+ SetProperty(object, name, value, NONE, strict_mode));
} else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
// Setting read only property in strict mode.
Handle<Object> error =
@@ -9121,6 +9068,10 @@
FlattenString(str);
CONVERT_ARG_CHECKED(JSArray, output, 1);
+
+ MaybeObject* maybe_result_array =
+ output->EnsureCanContainNonSmiElements();
+ if (maybe_result_array->IsFailure()) return maybe_result_array;
RUNTIME_ASSERT(output->HasFastElements());
AssertNoAllocation no_allocation;
@@ -9306,6 +9257,9 @@
PropertyAttributes attributes = ABSENT;
BindingFlags binding_flags;
while (true) {
+ // Don't follow context chains in Context::Lookup and implement the loop
+ // up the context chain here, so that we can know the context where eval
+ // was found.
receiver = context->Lookup(isolate->factory()->eval_symbol(),
FOLLOW_PROTOTYPE_CHAIN,
&index,
@@ -9421,7 +9375,7 @@
ASSERT(args.length() == 2);
CONVERT_CHECKED(JSArray, array, args[0]);
CONVERT_CHECKED(JSObject, element, args[1]);
- RUNTIME_ASSERT(array->HasFastElements());
+ RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
int length = Smi::cast(array->length())->value();
FixedArray* elements = FixedArray::cast(array->elements());
for (int i = 0; i < length; i++) {
@@ -9504,9 +9458,11 @@
isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
Handle<Map> map;
if (fast_elements_) {
- map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
+ map = isolate_->factory()->GetElementsTransitionMap(array,
+ FAST_ELEMENTS);
} else {
- map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
+ map = isolate_->factory()->GetElementsTransitionMap(array,
+ DICTIONARY_ELEMENTS);
}
array->set_map(*map);
array->set_length(*length);
@@ -9650,6 +9606,7 @@
List<uint32_t>* indices) {
ElementsKind kind = object->GetElementsKind();
switch (kind) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
Handle<FixedArray> elements(FixedArray::cast(object->elements()));
uint32_t length = static_cast<uint32_t>(elements->length());
@@ -9769,6 +9726,7 @@
ArrayConcatVisitor* visitor) {
uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
switch (receiver->GetElementsKind()) {
+ case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
// Run through the elements FixedArray and use HasElement and GetElement
// to check the prototype for missing elements.
@@ -9997,15 +9955,17 @@
CONVERT_CHECKED(JSArray, to, args[1]);
FixedArrayBase* new_elements = from->elements();
MaybeObject* maybe_new_map;
+ ElementsKind elements_kind;
if (new_elements->map() == isolate->heap()->fixed_array_map() ||
new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
- maybe_new_map = to->map()->GetFastElementsMap();
+ elements_kind = FAST_ELEMENTS;
} else if (new_elements->map() ==
isolate->heap()->fixed_double_array_map()) {
- maybe_new_map = to->map()->GetFastDoubleElementsMap();
+ elements_kind = FAST_DOUBLE_ELEMENTS;
} else {
- maybe_new_map = to->map()->GetSlowElementsMap();
+ elements_kind = DICTIONARY_ELEMENTS;
}
+ maybe_new_map = to->GetElementsTransitionMap(elements_kind);
Object* new_map;
if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
to->set_map(Map::cast(new_map));
@@ -10090,7 +10050,9 @@
}
return *isolate->factory()->NewJSArrayWithElements(keys);
} else {
- ASSERT(array->HasFastElements() || array->HasFastDoubleElements());
+ ASSERT(array->HasFastElements() ||
+ array->HasFastSmiOnlyElements() ||
+ array->HasFastDoubleElements());
Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
// -1 means start of array.
single_interval->set(0, Smi::FromInt(-1));
@@ -10209,8 +10171,8 @@
case CALLBACKS: {
Object* structure = result->GetCallbackObject();
if (structure->IsForeign() || structure->IsAccessorInfo()) {
- MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
- receiver, structure, name, result->holder());
+ MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
+ receiver, structure, name);
if (!maybe_value->ToObject(&value)) {
if (maybe_value->IsRetryAfterGC()) return maybe_value;
ASSERT(maybe_value->IsException());
@@ -11460,48 +11422,53 @@
int target_start_position = RelocInfo::kNoPosition;
Handle<SharedFunctionInfo> target;
while (!done) {
- HeapIterator iterator;
- for (HeapObject* obj = iterator.next();
- obj != NULL; obj = iterator.next()) {
- if (obj->IsSharedFunctionInfo()) {
- Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
- if (shared->script() == *script) {
- // If the SharedFunctionInfo found has the requested script data and
- // contains the source position it is a candidate.
- int start_position = shared->function_token_position();
- if (start_position == RelocInfo::kNoPosition) {
- start_position = shared->start_position();
- }
- if (start_position <= position &&
- position <= shared->end_position()) {
- // If there is no candidate or this function is within the current
- // candidate this is the new candidate.
- if (target.is_null()) {
- target_start_position = start_position;
- target = shared;
- } else {
- if (target_start_position == start_position &&
- shared->end_position() == target->end_position()) {
- // If a top-level function contain only one function
- // declartion the source for the top-level and the function is
- // the same. In that case prefer the non top-level function.
- if (!shared->is_toplevel()) {
+ { // Extra scope for iterator and no-allocation.
+ isolate->heap()->EnsureHeapIsIterable();
+ AssertNoAllocation no_alloc_during_heap_iteration;
+ HeapIterator iterator;
+ for (HeapObject* obj = iterator.next();
+ obj != NULL; obj = iterator.next()) {
+ if (obj->IsSharedFunctionInfo()) {
+ Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
+ if (shared->script() == *script) {
+ // If the SharedFunctionInfo found has the requested script data and
+ // contains the source position it is a candidate.
+ int start_position = shared->function_token_position();
+ if (start_position == RelocInfo::kNoPosition) {
+ start_position = shared->start_position();
+ }
+ if (start_position <= position &&
+ position <= shared->end_position()) {
+ // If there is no candidate or this function is within the current
+ // candidate this is the new candidate.
+ if (target.is_null()) {
+ target_start_position = start_position;
+ target = shared;
+ } else {
+ if (target_start_position == start_position &&
+ shared->end_position() == target->end_position()) {
+ // If a top-level function contain only one function
+ // declartion the source for the top-level and the
+ // function is the same. In that case prefer the non
+ // top-level function.
+ if (!shared->is_toplevel()) {
+ target_start_position = start_position;
+ target = shared;
+ }
+ } else if (target_start_position <= start_position &&
+ shared->end_position() <= target->end_position()) {
+ // This containment check includes equality as a function
+ // inside a top-level function can share either start or end
+ // position with the top-level function.
target_start_position = start_position;
target = shared;
}
- } else if (target_start_position <= start_position &&
- shared->end_position() <= target->end_position()) {
- // This containment check includes equality as a function inside
- // a top-level function can share either start or end position
- // with the top-level function.
- target_start_position = start_position;
- target = shared;
}
}
}
}
- }
- }
+ } // End for loop.
+ } // End No allocation scope.
if (target.is_null()) {
return isolate->heap()->undefined_value();
@@ -11516,7 +11483,7 @@
// functions which might contain the requested source position.
CompileLazyShared(target, KEEP_EXCEPTION);
}
- }
+ } // End while loop.
return *target;
}
@@ -11966,6 +11933,8 @@
Handle<Object> result =
Execution::Call(compiled_function, receiver, 0, NULL,
&has_pending_exception);
+ // Clear the oneshot breakpoints so that the debugger does not step further.
+ isolate->debug()->ClearStepping();
if (has_pending_exception) return Failure::Exception();
return *result;
}
@@ -11993,13 +11962,14 @@
// Return result as a JS array.
Handle<JSObject> result =
isolate->factory()->NewJSObject(isolate->array_function());
- Handle<JSArray>::cast(result)->SetContent(*instances);
+ isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
return *result;
}
// Helper function used by Runtime_DebugReferencedBy below.
-static int DebugReferencedBy(JSObject* target,
+static int DebugReferencedBy(HeapIterator* iterator,
+ JSObject* target,
Object* instance_filter, int max_references,
FixedArray* instances, int instances_size,
JSFunction* arguments_function) {
@@ -12009,9 +11979,8 @@
// Iterate the heap.
int count = 0;
JSObject* last = NULL;
- HeapIterator iterator;
HeapObject* heap_obj = NULL;
- while (((heap_obj = iterator.next()) != NULL) &&
+ while (((heap_obj = iterator->next()) != NULL) &&
(max_references == 0 || count < max_references)) {
// Only look at all JSObjects.
if (heap_obj->IsJSObject()) {
@@ -12076,7 +12045,11 @@
ASSERT(args.length() == 3);
// First perform a full GC in order to avoid references from dead objects.
- isolate->heap()->CollectAllGarbage(false);
+ isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
+ // The heap iterator reserves the right to do a GC to make the heap iterable.
+ // Due to the GC above we know it won't need to do that, but it seems cleaner
+ // to get the heap iterator constructed before we start having unprotected
+ // Object* locals that are not protected by handles.
// Check parameters.
CONVERT_CHECKED(JSObject, target, args[0]);
@@ -12086,6 +12059,7 @@
CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
RUNTIME_ASSERT(max_references >= 0);
+
// Get the constructor function for context extension and arguments array.
JSObject* arguments_boilerplate =
isolate->context()->global_context()->arguments_boilerplate();
@@ -12094,7 +12068,9 @@
// Get the number of referencing objects.
int count;
- count = DebugReferencedBy(target, instance_filter, max_references,
+ HeapIterator heap_iterator;
+ count = DebugReferencedBy(&heap_iterator,
+ target, instance_filter, max_references,
NULL, 0, arguments_function);
// Allocate an array to hold the result.
@@ -12105,30 +12081,34 @@
FixedArray* instances = FixedArray::cast(object);
// Fill the referencing objects.
- count = DebugReferencedBy(target, instance_filter, max_references,
+ // AllocateFixedArray above does not make the heap non-iterable.
+ ASSERT(HEAP->IsHeapIterable());
+ HeapIterator heap_iterator2;
+ count = DebugReferencedBy(&heap_iterator2,
+ target, instance_filter, max_references,
instances, count, arguments_function);
// Return result as JS array.
Object* result;
- { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
+ MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
isolate->context()->global_context()->array_function());
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- JSArray::cast(result)->SetContent(instances);
- return result;
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ return JSArray::cast(result)->SetContent(instances);
}
// Helper function used by Runtime_DebugConstructedBy below.
-static int DebugConstructedBy(JSFunction* constructor, int max_references,
- FixedArray* instances, int instances_size) {
+static int DebugConstructedBy(HeapIterator* iterator,
+ JSFunction* constructor,
+ int max_references,
+ FixedArray* instances,
+ int instances_size) {
AssertNoAllocation no_alloc;
// Iterate the heap.
int count = 0;
- HeapIterator iterator;
HeapObject* heap_obj = NULL;
- while (((heap_obj = iterator.next()) != NULL) &&
+ while (((heap_obj = iterator->next()) != NULL) &&
(max_references == 0 || count < max_references)) {
// Only look at all JSObjects.
if (heap_obj->IsJSObject()) {
@@ -12156,7 +12136,7 @@
ASSERT(args.length() == 2);
// First perform a full GC in order to avoid dead objects.
- isolate->heap()->CollectAllGarbage(false);
+ isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
// Check parameters.
CONVERT_CHECKED(JSFunction, constructor, args[0]);
@@ -12165,7 +12145,12 @@
// Get the number of referencing objects.
int count;
- count = DebugConstructedBy(constructor, max_references, NULL, 0);
+ HeapIterator heap_iterator;
+ count = DebugConstructedBy(&heap_iterator,
+ constructor,
+ max_references,
+ NULL,
+ 0);
// Allocate an array to hold the result.
Object* object;
@@ -12174,8 +12159,14 @@
}
FixedArray* instances = FixedArray::cast(object);
+ ASSERT(HEAP->IsHeapIterable());
// Fill the referencing objects.
- count = DebugConstructedBy(constructor, max_references, instances, count);
+ HeapIterator heap_iterator2;
+ count = DebugConstructedBy(&heap_iterator2,
+ constructor,
+ max_references,
+ instances,
+ count);
// Return result as JS array.
Object* result;
@@ -12183,8 +12174,7 @@
isolate->context()->global_context()->array_function());
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- JSArray::cast(result)->SetContent(instances);
- return result;
+ return JSArray::cast(result)->SetContent(instances);
}
@@ -12248,14 +12238,15 @@
}
-static int FindSharedFunctionInfosForScript(Script* script,
+static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
+ Script* script,
FixedArray* buffer) {
AssertNoAllocation no_allocations;
-
int counter = 0;
int buffer_size = buffer->length();
- HeapIterator iterator;
- for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
+ for (HeapObject* obj = iterator->next();
+ obj != NULL;
+ obj = iterator->next()) {
ASSERT(obj != NULL);
if (!obj->IsSharedFunctionInfo()) {
continue;
@@ -12281,16 +12272,30 @@
HandleScope scope(isolate);
CONVERT_CHECKED(JSValue, script_value, args[0]);
+
Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
const int kBufferSize = 32;
Handle<FixedArray> array;
array = isolate->factory()->NewFixedArray(kBufferSize);
- int number = FindSharedFunctionInfosForScript(*script, *array);
+ int number;
+ {
+ isolate->heap()->EnsureHeapIsIterable();
+ AssertNoAllocation no_allocations;
+ HeapIterator heap_iterator;
+ Script* scr = *script;
+ FixedArray* arr = *array;
+ number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
+ }
if (number > kBufferSize) {
array = isolate->factory()->NewFixedArray(number);
- FindSharedFunctionInfosForScript(*script, *array);
+ isolate->heap()->EnsureHeapIsIterable();
+ AssertNoAllocation no_allocations;
+ HeapIterator heap_iterator;
+ Script* scr = *script;
+ FixedArray* arr = *array;
+ FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
}
Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
@@ -12771,6 +12776,8 @@
// Scan the heap for Script objects to find the script with the requested
// script data.
Handle<Script> script;
+ script_name->GetHeap()->EnsureHeapIsIterable();
+ AssertNoAllocation no_allocation_during_heap_iteration;
HeapIterator iterator;
HeapObject* obj = NULL;
while (script.is_null() && ((obj = iterator.next()) != NULL)) {
@@ -12983,7 +12990,7 @@
Handle<Object> receiver(isolate->global_context()->global());
// This handle is nor shared, nor used later, so it's safe.
Object** argv[] = { key_handle.location() };
- bool pending_exception = false;
+ bool pending_exception;
value = Execution::Call(factory,
receiver,
1,
@@ -13139,6 +13146,7 @@
return isolate->heap()->ToBoolean(obj->Has##Name()); \
}
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
@@ -13222,6 +13230,9 @@
Isolate* isolate = Isolate::Current();
Failure* failure = Failure::cast(result);
if (failure->IsRetryAfterGC()) {
+ if (isolate->heap()->new_space()->AddFreshPage()) {
+ return;
+ }
// Try to do a garbage collection; ignore it if it fails. The C
// entry stub will throw an out-of-memory exception in that case.
isolate->heap()->CollectGarbage(failure->allocation_space());
@@ -13229,7 +13240,7 @@
// Handle last resort GC and make sure to allow future allocations
// to grow the heap without causing GCs (if possible).
isolate->counters()->gc_last_resort_from_js()->Increment();
- isolate->heap()->CollectAllGarbage(false);
+ isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
}
}