| Index: src/runtime.cc
|
| ===================================================================
|
| --- src/runtime.cc (revision 9531)
|
| +++ src/runtime.cc (working copy)
|
| @@ -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
|
| }
|
| -#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.
|
| + // 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);
|
| - 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.
|
| + 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,12 +1552,13 @@
|
|
|
| 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;
|
| ContextLookupFlags flags = FOLLOW_CHAINS;
|
| @@ -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);
|
| }
|
| }
|
|
|
|
|