Enabled new regular expression engine.
Made a number of changes to the debugger protocol.
Fixed a number of bugs in the preemption support.
Added -p option to the developer shell to run files in parallel using preemption.
Fixed a number of minor bugs (including issues 176, 187, 189, 192, 193, 198 and 201).
Fixed a number of bugs in the serialization/deserialization support for the ARM platform.
git-svn-id: http://v8.googlecode.com/svn/trunk@1172 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/runtime.cc b/src/runtime.cc
index fd36724..18d6c03 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -161,15 +161,16 @@
for (int index = 0; index < length; index +=2) {
Handle<Object> key(constant_properties->get(index+0));
Handle<Object> value(constant_properties->get(index+1));
+ Handle<Object> result;
uint32_t element_index = 0;
if (key->IsSymbol()) {
// If key is a symbol it is not an array element.
Handle<String> name(String::cast(*key));
ASSERT(!name->AsArrayIndex(&element_index));
- SetProperty(boilerplate, name, value, NONE);
+ result = SetProperty(boilerplate, name, value, NONE);
} else if (Array::IndexFromObject(*key, &element_index)) {
// Array index (uint32).
- SetElement(boilerplate, element_index, value);
+ result = SetElement(boilerplate, element_index, value);
} else {
// Non-uint32 number.
ASSERT(key->IsNumber());
@@ -178,8 +179,13 @@
Vector<char> buffer(arr, ARRAY_SIZE(arr));
const char* str = DoubleToCString(num, buffer);
Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
- SetProperty(boilerplate, name, value, NONE);
+ result = SetProperty(boilerplate, name, value, NONE);
}
+ // If setting the property on the boilerplate throws an
+ // exception, the exception is converted to an empty handle in
+ // the handle based operations. In that case, we need to
+ // convert back to an exception.
+ if (result.is_null()) return Failure::Exception();
}
}
@@ -758,56 +764,94 @@
int index;
PropertyAttributes attributes;
- ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
+ ContextLookupFlags flags = FOLLOW_CHAINS;
Handle<Object> holder =
context->Lookup(name, flags, &index, &attributes);
- // The property should always be present. It is always declared
- // before being initialized through DeclareContextSlot.
- ASSERT(attributes != ABSENT && (attributes & READ_ONLY) != 0);
-
- // If the slot is in the context, we set it but only if it hasn't
- // been set before.
+ // 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) {
- // The constant context slot should always be in the function
- // context; not in any outer context nor in the arguments object.
- ASSERT(holder.is_identical_to(context));
- if (context->get(index)->IsTheHole()) {
- context->set(index, *value);
+ // Property was found in a context.
+ if (holder->IsContext()) {
+ // The holder cannot be the function context. If it is, there
+ // should have been a const redeclaration error when declaring
+ // the const property.
+ ASSERT(!holder.is_identical_to(context));
+ if ((attributes & READ_ONLY) == 0) {
+ Handle<Context>::cast(holder)->set(index, *value);
+ }
+ } else {
+ // The holder is an arguments object.
+ ASSERT((attributes & READ_ONLY) == 0);
+ Handle<JSObject>::cast(holder)->SetElement(index, *value);
}
return *value;
}
- // Otherwise, the slot must be in a JS object extension.
- Handle<JSObject> context_ext(JSObject::cast(*holder));
+ // The property could not be found, we introduce it in the global
+ // context.
+ if (attributes == ABSENT) {
+ Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
+ SetProperty(global, name, value, NONE);
+ return *value;
+ }
- // We must initialize the value only if it wasn't initialized
- // before, e.g. for const declarations in a loop. The property has
- // the hole value if it wasn't initialized yet. NOTE: We cannot use
- // GetProperty() to get the current value as it 'unholes' the value.
- LookupResult lookup;
- context_ext->LocalLookupRealNamedProperty(*name, &lookup);
- ASSERT(lookup.IsProperty()); // the property was declared
- ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
+ // The property was present in a context extension object.
+ Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
- PropertyType type = lookup.type();
- if (type == FIELD) {
- FixedArray* properties = context_ext->properties();
- int index = lookup.GetFieldIndex();
- if (properties->get(index)->IsTheHole()) {
- properties->set(index, *value);
- }
- } else if (type == NORMAL) {
- Dictionary* dictionary = context_ext->property_dictionary();
- int entry = lookup.GetDictionaryEntry();
- if (dictionary->ValueAt(entry)->IsTheHole()) {
- dictionary->ValueAtPut(entry, *value);
+ 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.
+ LookupResult lookup;
+ context_ext->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();
+ int index = lookup.GetFieldIndex();
+ if (properties->get(index)->IsTheHole()) {
+ properties->set(index, *value);
+ }
+ } else if (type == NORMAL) {
+ Dictionary* dictionary = context_ext->property_dictionary();
+ int entry = lookup.GetDictionaryEntry();
+ if (dictionary->ValueAt(entry)->IsTheHole()) {
+ dictionary->ValueAtPut(entry, *value);
+ }
+ } else {
+ // We should not reach here. Any real, named property should be
+ // either a field or a dictionary slot.
+ UNREACHABLE();
}
} else {
- // We should not reach here. Any real, named property should be
- // either a field or a dictionary slot.
- UNREACHABLE();
+ // The property was found in a different context extension object.
+ // Set it if it is not a read-only property.
+ if ((attributes & READ_ONLY) == 0) {
+ Handle<Object> set = SetProperty(context_ext, name, value, attributes);
+ // Setting a property might throw an exception. Exceptions
+ // are converted to empty handles in handle operations. We
+ // need to convert back to exceptions here.
+ if (set.is_null()) {
+ ASSERT(Top::has_pending_exception());
+ return Failure::Exception();
+ }
+ }
}
+
return *value;
}
@@ -1022,7 +1066,7 @@
// Flatten the string. If someone wants to get a char at an index
// in a cons string, it is likely that more indices will be
// accessed.
- subject->TryFlatten(StringShape(subject));
+ subject->TryFlattenIfNotFlat(StringShape(subject));
StringShape shape(subject);
if (i >= static_cast<uint32_t>(subject->length(shape))) {
return Heap::nan_value();
@@ -1493,8 +1537,8 @@
CONVERT_CHECKED(String, pat, args[1]);
Object* index = args[2];
- sub->TryFlatten(StringShape(sub));
- pat->TryFlatten(StringShape(pat));
+ sub->TryFlattenIfNotFlat(StringShape(sub));
+ pat->TryFlattenIfNotFlat(StringShape(pat));
StringShape sub_shape(sub);
StringShape pat_shape(pat);
@@ -1553,8 +1597,8 @@
int d = str1->Get(shape1, 0) - str2->Get(shape2, 0);
if (d != 0) return Smi::FromInt(d);
- str1->TryFlatten(shape1); // Shapes are no longer valid now!
- str2->TryFlatten(shape2);
+ str1->TryFlattenIfNotFlat(shape1); // Shapes are no longer valid now!
+ str2->TryFlattenIfNotFlat(shape2);
static StringInputBuffer buf1;
static StringInputBuffer buf2;
@@ -1691,7 +1735,7 @@
static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
StringShape shape(*string);
if (index < static_cast<uint32_t>(string->length(shape))) {
- string->TryFlatten(shape); // Invalidates shape!
+ string->TryFlattenIfNotFlat(shape); // Invalidates shape!
return LookupSingleCharacterStringFromCode(
string->Get(StringShape(*string), index));
}
@@ -1884,7 +1928,7 @@
result = SetElement(js_object, index, value);
} else {
Handle<String> key_string = Handle<String>::cast(key);
- key_string->TryFlatten(StringShape(*key_string));
+ key_string->TryFlattenIfNotFlat(StringShape(*key_string));
result = SetProperty(js_object, key_string, value, attr);
}
if (result.is_null()) return Failure::Exception();
@@ -2156,7 +2200,7 @@
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_CHECKED(String, subject, args[0]);
- subject->TryFlatten(StringShape(subject));
+ subject->TryFlattenIfNotFlat(StringShape(subject));
return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
}
@@ -2239,7 +2283,7 @@
ASSERT(args.length() == 1);
CONVERT_CHECKED(String, source, args[0]);
- source->TryFlatten(StringShape(source));
+ source->TryFlattenIfNotFlat(StringShape(source));
int escaped_length = 0;
int length = source->length();
@@ -2353,7 +2397,7 @@
ASSERT(args.length() == 1);
CONVERT_CHECKED(String, source, args[0]);
- source->TryFlatten(StringShape(source));
+ source->TryFlattenIfNotFlat(StringShape(source));
StringShape source_shape(source);
bool ascii = true;
@@ -2402,7 +2446,7 @@
CONVERT_DOUBLE_CHECKED(n, args[1]);
int radix = FastD2I(n);
- s->TryFlatten(StringShape(s));
+ s->TryFlattenIfNotFlat(StringShape(s));
StringShape shape(s);
@@ -2475,7 +2519,7 @@
NoHandleAllocation ha;
CONVERT_CHECKED(String, s, args[0]);
- s->TryFlatten(StringShape(s));
+ s->TryFlattenIfNotFlat(StringShape(s));
StringShape shape(s);
int raw_string_length = s->length(shape);
@@ -3079,8 +3123,8 @@
if (d < 0) return Smi::FromInt(LESS);
else if (d > 0) return Smi::FromInt(GREATER);
- x->TryFlatten(x_shape); // Shapes are no longer valid!
- y->TryFlatten(y_shape);
+ x->TryFlattenIfNotFlat(x_shape); // Shapes are no longer valid!
+ y->TryFlattenIfNotFlat(y_shape);
static StringInputBuffer bufx;
static StringInputBuffer bufy;
@@ -3734,7 +3778,9 @@
ASSERT(args.length() == 1);
// First check if this is a real stack overflow.
- if (StackGuard::IsStackOverflow()) return Runtime_StackOverflow(args);
+ if (StackGuard::IsStackOverflow()) {
+ return Runtime_StackOverflow(args);
+ }
return Execution::HandleStackGuardInterrupt();
}
@@ -4536,6 +4582,21 @@
}
+// Find the length of the prototype chain that is to to handled as one. If a
+// prototype object is hidden it is to be viewed as part of the the object it
+// is prototype for.
+static int LocalPrototypeChainLength(JSObject* obj) {
+ int count = 1;
+ Object* proto = obj->GetPrototype();
+ while (proto->IsJSObject() &&
+ JSObject::cast(proto)->map()->is_hidden_prototype()) {
+ count++;
+ proto = JSObject::cast(proto)->GetPrototype();
+ }
+ return count;
+}
+
+
static Object* DebugLookupResultValue(Object* receiver, LookupResult* result,
bool* caught_exception) {
Object* value;
@@ -4611,6 +4672,13 @@
CONVERT_ARG_CHECKED(JSObject, obj, 0);
CONVERT_ARG_CHECKED(String, name, 1);
+ // Skip the global proxy as it has no properties and always delegates to the
+ // real global object.
+ if (obj->IsJSGlobalProxy()) {
+ obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
+ }
+
+
// Check if the name is trivially convertible to an index and get the element
// if so.
uint32_t index;
@@ -4621,9 +4689,22 @@
return *Factory::NewJSArrayWithElements(details);
}
- // Perform standard local lookup on the object.
+ // Find the number of objects making up this.
+ int length = LocalPrototypeChainLength(*obj);
+
+ // Try local lookup on each of the objects.
LookupResult result;
- obj->LocalLookup(*name, &result);
+ Handle<JSObject> jsproto = obj;
+ for (int i = 0; i < length; i++) {
+ jsproto->LocalLookup(*name, &result);
+ if (result.IsProperty()) {
+ break;
+ }
+ if (i < length - 1) {
+ jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
+ }
+ }
+
if (result.IsProperty()) {
bool caught_exception = false;
Handle<Object> value(DebugLookupResultValue(*obj, &result,
@@ -4676,9 +4757,43 @@
}
CONVERT_ARG_CHECKED(JSObject, obj, 0);
- int n = obj->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
- Handle<FixedArray> names = Factory::NewFixedArray(n);
- obj->GetLocalPropertyNames(*names);
+ // Skip the global proxy as it has no properties and always delegates to the
+ // real global object.
+ if (obj->IsJSGlobalProxy()) {
+ obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
+ }
+
+ // Find the number of objects making up this.
+ int length = LocalPrototypeChainLength(*obj);
+
+ // Find the number of local properties for each of the objects.
+ int* local_property_count = NewArray<int>(length);
+ int total_property_count = 0;
+ Handle<JSObject> jsproto = obj;
+ for (int i = 0; i < length; i++) {
+ int n;
+ n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
+ local_property_count[i] = n;
+ total_property_count += n;
+ if (i < length - 1) {
+ jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
+ }
+ }
+
+ // Allocate an array with storage for all the property names.
+ Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
+
+ // Get the property names.
+ jsproto = obj;
+ for (int i = 0; i < length; i++) {
+ jsproto->GetLocalPropertyNames(*names,
+ i == 0 ? 0 : local_property_count[i - 1]);
+ if (i < length - 1) {
+ jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
+ }
+ }
+
+ DeleteArray(local_property_count);
return *Factory::NewJSArrayWithElements(names);
}
@@ -5806,12 +5921,15 @@
}
-static Object* Runtime_GetPrototype(Arguments args) {
+// Find the effective prototype object as returned by __proto__.
+// args[0]: the object to find the prototype for.
+static Object* Runtime_DebugGetPrototype(Arguments args) {
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSObject, obj, args[0]);
- return obj->GetPrototype();
+ // Use the __proto__ accessor.
+ return Accessors::ObjectPrototype.getter(obj, NULL);
}