Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Unified Diff: src/runtime.cc

Issue 18842: Experimental: periodic merge of the bleeding_edge branch to the... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/toiger/
Patch Set: Created 11 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/runtime.h ('k') | src/scanner.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/runtime.cc
===================================================================
--- src/runtime.cc (revision 1168)
+++ src/runtime.cc (working copy)
@@ -154,22 +154,23 @@
&is_result_from_cache);
Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
- { // Add the constant propeties to the boilerplate.
+ { // Add the constant properties to the boilerplate.
int length = constant_properties->length();
OptimizedObjectForAddingMultipleProperties opt(boilerplate,
!is_result_from_cache);
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();
}
}
@@ -215,6 +221,23 @@
}
+static Object* Runtime_CreateCatchExtensionObject(Arguments args) {
+ ASSERT(args.length() == 2);
+ CONVERT_CHECKED(String, key, args[0]);
+ Object* value = args[1];
+ // Create a catch context extension object.
+ JSFunction* constructor =
+ Top::context()->global_context()->context_extension_function();
+ Object* object = Heap::AllocateJSObject(constructor);
+ if (object->IsFailure()) return object;
+ // Assign the exception value to the catch variable and make sure
+ // that the catch variable is DontDelete.
+ value = JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
+ if (value->IsFailure()) return value;
+ return object;
+}
+
+
static Object* Runtime_ClassOf(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -343,8 +366,16 @@
static Object* Runtime_DisableAccessChecks(Arguments args) {
ASSERT(args.length() == 1);
CONVERT_CHECKED(HeapObject, object, args[0]);
- bool needs_access_checks = object->map()->is_access_check_needed();
- object->map()->set_is_access_check_needed(false);
+ Map* old_map = object->map();
+ bool needs_access_checks = old_map->is_access_check_needed();
+ if (needs_access_checks) {
+ // Copy map so it won't interfere constructor's initial map.
+ Object* new_map = old_map->CopyDropTransitions();
+ if (new_map->IsFailure()) return new_map;
+
+ Map::cast(new_map)->set_is_access_check_needed(false);
+ object->set_map(Map::cast(new_map));
+ }
return needs_access_checks ? Heap::true_value() : Heap::false_value();
}
@@ -352,7 +383,15 @@
static Object* Runtime_EnableAccessChecks(Arguments args) {
ASSERT(args.length() == 1);
CONVERT_CHECKED(HeapObject, object, args[0]);
- object->map()->set_is_access_check_needed(true);
+ Map* old_map = object->map();
+ if (!old_map->is_access_check_needed()) {
+ // Copy map so it won't interfere constructor's initial map.
+ Object* new_map = old_map->CopyDropTransitions();
+ if (new_map->IsFailure()) return new_map;
+
+ Map::cast(new_map)->set_is_access_check_needed(true);
+ object->set_map(Map::cast(new_map));
+ }
return Heap::undefined_value();
}
@@ -725,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);
+ 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 if (type == NORMAL) {
- Dictionary* dictionary = context_ext->property_dictionary();
- int entry = lookup.GetDictionaryEntry();
- if (dictionary->ValueAt(entry)->IsTheHole()) {
- dictionary->ValueAtPut(entry, *value);
+ } else {
+ // 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();
+ }
}
- } else {
- // We should not reach here. Any real, named property should be
- // either a field or a dictionary slot.
- UNREACHABLE();
}
+
return *value;
}
@@ -989,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();
@@ -1460,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);
@@ -1520,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;
@@ -1658,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));
}
@@ -1719,7 +1796,7 @@
name = Handle<String>::cast(converted);
}
- // Check if the name is trivially convertable to an index and get
+ // Check if the name is trivially convertible to an index and get
// the element if so.
if (name->AsArrayIndex(&index)) {
return GetElementOrCharAt(object, index);
@@ -1751,7 +1828,7 @@
// itself.
//
// The global proxy objects has to be excluded since LocalLookup on
- // the global proxy object can return a valid result eventhough the
+ // the global proxy object can return a valid result even though the
// global proxy object never has properties. This is the case
// because the global proxy object forwards everything to its hidden
// prototype including local lookups.
@@ -1851,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();
@@ -2123,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));
}
@@ -2206,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();
@@ -2320,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;
@@ -2369,7 +2446,7 @@
CONVERT_DOUBLE_CHECKED(n, args[1]);
int radix = FastD2I(n);
- s->TryFlatten(StringShape(s));
+ s->TryFlattenIfNotFlat(StringShape(s));
StringShape shape(s);
@@ -2442,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);
@@ -2987,7 +3064,7 @@
// same as the lexicographic order of the string representations.
if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
- // If only one of the intergers is negative the negative number is
+ // If only one of the integers is negative the negative number is
// smallest because the char code of '-' is less than the char code
// of any digit. Otherwise, we make both values positive.
if (x_value < 0 || y_value < 0) {
@@ -3046,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;
@@ -3325,7 +3402,7 @@
if (constructor->IsJSFunction()) {
JSFunction* function = JSFunction::cast(constructor);
- // Handle steping into constructors if step into is active.
+ // Handle stepping into constructors if step into is active.
if (Debug::StepInActive()) {
HandleScope scope;
Debug::HandleStepIn(Handle<JSFunction>(function), 0, true);
@@ -3701,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();
}
@@ -4503,32 +4582,64 @@
}
-static Object* DebugLookupResultValue(Object* obj, String* name,
- LookupResult* result,
+// 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;
switch (result->type()) {
- case NORMAL:
+ case NORMAL: {
+ Dictionary* dict =
+ JSObject::cast(result->holder())->property_dictionary();
+ value = dict->ValueAt(result->GetDictionaryEntry());
+ if (value->IsTheHole()) {
+ return Heap::undefined_value();
+ }
+ return value;
+ }
case FIELD:
+ value =
+ JSObject::cast(
+ result->holder())->FastPropertyAt(result->GetFieldIndex());
+ if (value->IsTheHole()) {
+ return Heap::undefined_value();
+ }
+ return value;
case CONSTANT_FUNCTION:
- return obj->GetProperty(name);
+ return result->GetConstantFunction();
case CALLBACKS: {
- // Get the property value. If there is an exception it must be thown from
- // a JavaScript getter.
- Object* value;
- value = obj->GetProperty(name);
- if (value->IsException()) {
- if (caught_exception != NULL) {
- *caught_exception = true;
+ Object* structure = result->GetCallbackObject();
+ if (structure->IsProxy()) {
+ AccessorDescriptor* callback =
+ reinterpret_cast<AccessorDescriptor*>(
+ Proxy::cast(structure)->proxy());
+ value = (callback->getter)(receiver, callback->data);
+ if (value->IsFailure()) {
+ value = Top::pending_exception();
+ Top::clear_pending_exception();
+ if (caught_exception != NULL) {
+ *caught_exception = true;
+ }
}
- value = Top::pending_exception();
- Top::optional_reschedule_exception(true);
+ return value;
+ } else {
+ return Heap::undefined_value();
}
- ASSERT(!Top::has_pending_exception());
- ASSERT(!Top::external_caught_exception());
- return value;
}
case INTERCEPTOR:
- return obj->GetProperty(name);
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
@@ -4561,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;
@@ -4571,12 +4689,25 @@
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, *name, &result,
+ Handle<Object> value(DebugLookupResultValue(*obj, &result,
&caught_exception));
// If the callback object is a fixed array then it contains JavaScript
// getter and/or setter.
@@ -4610,7 +4741,7 @@
LookupResult result;
obj->Lookup(*name, &result);
if (result.IsProperty()) {
- return DebugLookupResultValue(*obj, *name, &result, NULL);
+ return DebugLookupResultValue(*obj, &result, NULL);
}
return Heap::undefined_value();
}
@@ -4626,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);
}
@@ -5091,7 +5256,7 @@
}
if (start_position <= position &&
position <= shared->end_position()) {
- // If there is no candidate or this function is within the currrent
+ // 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;
@@ -5309,7 +5474,7 @@
// Evaluate a piece of JavaScript in the context of a stack frame for
-// debugging. This is acomplished by creating a new context which in its
+// debugging. This is accomplished by creating a new context which in its
// extension part has all the parameters and locals of the function on the
// stack frame. A function which calls eval with the code to evaluate is then
// compiled in this context and called in this context. As this context
@@ -5420,7 +5585,7 @@
// Wrap the evaluation statement in a new function compiled in the newly
// created context. The function has one parameter which has to be called
// 'arguments'. This it to have access to what would have been 'arguments' in
- // the function beeing debugged.
+ // the function being debugged.
// function(arguments,__source__) {return eval(__source__);}
static const char* source_str =
"function(arguments,__source__){return eval(__source__);}";
@@ -5535,7 +5700,7 @@
ASSERT(args.length() == 0);
// Perform two GCs to get rid of all unreferenced scripts. The first GC gets
- // rid of all the cached script wrappes and the second gets rid of the
+ // rid of all the cached script wrappers and the second gets rid of the
// scripts which is no longer referenced.
Heap::CollectAllGarbage();
Heap::CollectAllGarbage();
@@ -5756,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);
}
« no previous file with comments | « src/runtime.h ('k') | src/scanner.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698