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); |
} |
} |