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

Unified Diff: src/runtime.cc

Issue 8404030: Version 3.7.1 (Closed) Base URL: http://v8.googlecode.com/svn/trunk/
Patch Set: Created 9 years, 2 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/runtime.js » ('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 9808)
+++ src/runtime.cc (working copy)
@@ -432,64 +432,77 @@
// Create the JSArray.
Handle<JSFunction> constructor(
JSFunction::GlobalContextFromLiterals(*literals)->array_function());
- Handle<Object> object = isolate->factory()->NewJSObject(constructor);
+ Handle<JSArray> object =
+ Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
- if (elements->length() > kSmiOnlyLiteralMinimumLength) {
- Handle<Map> smi_array_map = isolate->factory()->GetElementsTransitionMap(
- Handle<JSObject>::cast(object),
- FAST_SMI_ONLY_ELEMENTS);
- HeapObject::cast(*object)->set_map(*smi_array_map);
+ ElementsKind constant_elements_kind =
+ static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
+ Handle<FixedArrayBase> constant_elements_values(
+ FixedArrayBase::cast(elements->get(1)));
+
+ ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
+ constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
+ bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
+ constant_elements_kind > object->GetElementsKind();
+
+ if (!FLAG_smi_only_arrays &&
+ constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
+ constant_elements_kind != object->GetElementsKind()) {
+ allow_literal_kind_transition = true;
}
- const bool is_cow =
- (elements->map() == isolate->heap()->fixed_cow_array_map());
- Handle<FixedArray> copied_elements =
- is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
+ // If the ElementsKind of the constant values of the array literal are less
+ // specific than the ElementsKind of the boilerplate array object, change the
+ // boilerplate array object's map to reflect that kind.
+ if (allow_literal_kind_transition) {
+ Handle<Map> transitioned_array_map =
+ isolate->factory()->GetElementsTransitionMap(object,
+ constant_elements_kind);
+ object->set_map(*transitioned_array_map);
+ }
- Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
- bool has_non_smi = false;
- if (is_cow) {
- // Copy-on-write arrays must be shallow (and simple).
- 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;
+ Handle<FixedArrayBase> copied_elements_values;
+ if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
+ ASSERT(FLAG_smi_only_arrays);
+ copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
+ Handle<FixedDoubleArray>::cast(constant_elements_values));
+ } else {
+ ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
+ constant_elements_kind == FAST_ELEMENTS);
+ const bool is_cow =
+ (constant_elements_values->map() ==
+ isolate->heap()->fixed_cow_array_map());
+ if (is_cow) {
+ copied_elements_values = constant_elements_values;
+#if DEBUG
+ Handle<FixedArray> fixed_array_values =
+ Handle<FixedArray>::cast(copied_elements_values);
+ for (int i = 0; i < fixed_array_values->length(); i++) {
+ ASSERT(!fixed_array_values->get(i)->IsFixedArray());
}
- }
-#if DEBUG
- for (int i = 0; i < content->length(); i++) {
- ASSERT(!content->get(i)->IsFixedArray());
- }
#endif
- } else {
- for (int i = 0; i < content->length(); i++) {
- 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)));
- Handle<Object> result =
- 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;
+ } else {
+ Handle<FixedArray> fixed_array_values =
+ Handle<FixedArray>::cast(constant_elements_values);
+ Handle<FixedArray> fixed_array_values_copy =
+ isolate->factory()->CopyFixedArray(fixed_array_values);
+ copied_elements_values = fixed_array_values_copy;
+ for (int i = 0; i < fixed_array_values->length(); i++) {
+ Object* current = fixed_array_values->get(i);
+ if (current->IsFixedArray()) {
+ // The value contains the constant_properties of a
+ // simple object or array literal.
+ Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
+ Handle<Object> result =
+ CreateLiteralBoilerplate(isolate, literals, fa);
+ if (result.is_null()) return result;
+ fixed_array_values_copy->set(i, *result);
}
}
}
}
-
- // Set the elements.
- Handle<JSArray> js_object(Handle<JSArray>::cast(object));
- isolate->factory()->SetContent(js_object, content);
-
- if (has_non_smi && js_object->HasFastSmiOnlyElements()) {
- isolate->factory()->EnsureCanContainNonSmiElements(js_object);
- }
-
+ object->set_elements(*copied_elements_values);
+ object->set_length(Smi::FromInt(copied_elements_values->length()));
return object;
}
@@ -704,6 +717,82 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(JSSet, holder, 0);
+ Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
+ holder->set_table(*table);
+ return *holder;
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 2);
+ CONVERT_ARG_CHECKED(JSSet, holder, 0);
+ Handle<Object> key(args[1]);
+ Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
+ table = ObjectHashSetAdd(table, key);
+ holder->set_table(*table);
+ return isolate->heap()->undefined_symbol();
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 2);
+ CONVERT_ARG_CHECKED(JSSet, holder, 0);
+ Handle<Object> key(args[1]);
+ Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
+ return isolate->heap()->ToBoolean(table->Contains(*key));
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 2);
+ CONVERT_ARG_CHECKED(JSSet, holder, 0);
+ Handle<Object> key(args[1]);
+ Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
+ table = ObjectHashSetRemove(table, key);
+ holder->set_table(*table);
+ return isolate->heap()->undefined_symbol();
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(JSMap, holder, 0);
+ Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
+ holder->set_table(*table);
+ return *holder;
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 2);
+ CONVERT_ARG_CHECKED(JSMap, holder, 0);
+ Handle<Object> key(args[1]);
+ return ObjectHashTable::cast(holder->table())->Lookup(*key);
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 3);
+ CONVERT_ARG_CHECKED(JSMap, holder, 0);
+ Handle<Object> key(args[1]);
+ Handle<Object> value(args[2]);
+ Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
+ Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
+ holder->set_table(*new_table);
+ return *value;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
@@ -961,7 +1050,7 @@
HandleScope scope(isolate);
Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
- LookupResult result;
+ LookupResult result(isolate);
CONVERT_ARG_CHECKED(JSObject, obj, 0);
CONVERT_ARG_CHECKED(String, name, 1);
@@ -992,7 +1081,7 @@
case JSObject::INTERCEPTED_ELEMENT:
case JSObject::FAST_ELEMENT: {
elms->set(IS_ACCESSOR_INDEX, heap->false_value());
- Handle<Object> value = GetElement(obj, index);
+ Handle<Object> value = Object::GetElement(obj, index);
RETURN_IF_EMPTY_HANDLE(isolate, value);
elms->set(VALUE_INDEX, *value);
elms->set(WRITABLE_INDEX, heap->true_value());
@@ -1036,7 +1125,7 @@
case NORMAL: {
// This is a data property.
elms->set(IS_ACCESSOR_INDEX, heap->false_value());
- Handle<Object> value = GetElement(obj, index);
+ Handle<Object> value = Object::GetElement(obj, index);
ASSERT(!value.is_null());
elms->set(VALUE_INDEX, *value);
elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
@@ -1240,7 +1329,7 @@
if (value->IsUndefined() || is_const_property) {
// Lookup the property in the global object, and don't set the
// value of the variable if the property is already there.
- LookupResult lookup;
+ LookupResult lookup(isolate);
global->Lookup(*name, &lookup);
if (lookup.IsProperty()) {
// We found an existing property. Unless it was an interceptor
@@ -1267,7 +1356,7 @@
value = function;
}
- LookupResult lookup;
+ LookupResult lookup(isolate);
global->LocalLookup(*name, &lookup);
// Compute the property attributes. According to ECMA-262, section
@@ -1275,10 +1364,10 @@
// non-deletable. However, neither SpiderMonkey nor KJS creates the
// property as read-only, so we don't either.
int attr = NONE;
- if ((flags & kDeclareGlobalsEvalFlag) == 0) {
+ if (!DeclareGlobalsEvalFlag::decode(flags)) {
attr |= DONT_DELETE;
}
- bool is_native = (flags & kDeclareGlobalsNativeFlag) != 0;
+ bool is_native = DeclareGlobalsNativeFlag::decode(flags);
if (is_const_property || (is_native && is_function_declaration)) {
attr |= READ_ONLY;
}
@@ -1303,9 +1392,7 @@
value,
attributes));
} else {
- StrictModeFlag strict_mode =
- ((flags & kDeclareGlobalsStrictModeFlag) != 0) ? kStrictMode
- : kNonStrictMode;
+ StrictModeFlag strict_mode = DeclareGlobalsStrictModeFlag::decode(flags);
RETURN_IF_EMPTY_HANDLE(isolate,
SetProperty(global,
name,
@@ -1399,7 +1486,7 @@
// not real JSObjects.
if (initial_value->IsTheHole() &&
!object->IsJSContextExtensionObject()) {
- LookupResult lookup;
+ LookupResult lookup(isolate);
object->Lookup(*name, &lookup);
if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
return ThrowRedeclarationError(isolate, "const", name);
@@ -1443,7 +1530,7 @@
// Note that objects can have hidden prototypes, so we need to traverse
// the whole chain of hidden prototypes to do a 'local' lookup.
Object* object = global;
- LookupResult lookup;
+ LookupResult lookup(isolate);
while (object->IsJSObject() &&
JSObject::cast(object)->map()->is_hidden_prototype()) {
JSObject* raw_holder = JSObject::cast(object);
@@ -1497,7 +1584,7 @@
// add it as a local property even in case of callbacks in the
// prototype chain (this rules out using SetProperty).
// We use SetLocalPropertyIgnoreAttributes instead
- LookupResult lookup;
+ LookupResult lookup(isolate);
global->LocalLookup(*name, &lookup);
if (!lookup.IsProperty()) {
return global->SetLocalPropertyIgnoreAttributes(*name,
@@ -1614,7 +1701,7 @@
// 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;
+ LookupResult lookup(isolate);
object->LocalLookupRealNamedProperty(*name, &lookup);
ASSERT(lookup.IsProperty()); // the property was declared
ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
@@ -1663,19 +1750,6 @@
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_NonSmiElementStored) {
- ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSObject, object, 0);
- if (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);
@@ -1930,15 +2004,6 @@
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 1);
-
- CONVERT_CHECKED(JSFunction, fun, args[0]);
- fun->shared()->set_bound(true);
- return isolate->heap()->undefined_value();
-}
-
RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -2017,24 +2082,6 @@
}
-// Creates a local, readonly, property called length with the correct
-// length (when read by the user). This effectively overwrites the
-// interceptor used to normally provide the length.
-RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
- NoHandleAllocation ha;
- ASSERT(args.length() == 2);
- CONVERT_CHECKED(JSFunction, fun, args[0]);
- CONVERT_CHECKED(Smi, length, args[1]);
- MaybeObject* maybe_name =
- isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
- String* name;
- if (!maybe_name->To(&name)) return maybe_name;
- PropertyAttributes attr =
- static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
- return fun->AddProperty(name, length, attr, kNonStrictMode);
-}
-
-
RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -2137,13 +2184,12 @@
Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
Handle<SharedFunctionInfo> shared(fun->shared());
- if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
+ if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
return Failure::Exception();
}
// Since we don't store the source for this we should never
// optimize this.
shared->code()->set_optimizable(false);
-
// Set the code, scope info, formal parameter count,
// and the length of the target function.
target->shared()->set_code(shared->code());
@@ -4069,11 +4115,6 @@
return prototype->GetElement(index);
}
- return GetElement(object, index);
-}
-
-
-MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
return object->GetElement(index);
}
@@ -4162,7 +4203,7 @@
return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
}
// Lookup cache miss. Perform lookup and update the cache if appropriate.
- LookupResult result;
+ LookupResult result(isolate);
receiver->LocalLookup(key, &result);
if (result.IsProperty() && result.type() == FIELD) {
int offset = result.GetFieldIndex();
@@ -4217,7 +4258,7 @@
int unchecked = flag_attr->value();
RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
RUNTIME_ASSERT(!obj->IsNull());
- LookupResult result;
+ LookupResult result(isolate);
obj->LocalLookupRealNamedProperty(name, &result);
PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
@@ -4259,11 +4300,11 @@
uint32_t index;
bool is_element = name->AsArrayIndex(&index);
- // Special case for elements if any of the flags are true.
+ // Special case for elements if any of the flags might be involved.
// If elements are in fast case we always implicitly assume that:
// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
- if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
- is_element) {
+ if (is_element && (attr != NONE ||
+ js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
// Normalize the elements to enable attributes on the property.
if (js_object->IsJSGlobalProxy()) {
// We do not need to do access checks here since these has already
@@ -4301,7 +4342,7 @@
return *obj_value;
}
- LookupResult result;
+ LookupResult result(isolate);
js_object->LocalLookupRealNamedProperty(*name, &result);
// To be compatible with safari we do not change the value on API objects
@@ -4568,6 +4609,39 @@
}
+MaybeObject* TransitionElements(Handle<Object> object,
+ ElementsKind to_kind,
+ Isolate* isolate) {
+ HandleScope scope(isolate);
+ if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
+ ElementsKind from_kind =
+ Handle<JSObject>::cast(object)->map()->elements_kind();
+ if (Map::IsValidElementsTransition(from_kind, to_kind)) {
+ Handle<Object> result =
+ TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
+ if (result.is_null()) return isolate->ThrowIllegalOperation();
+ return *result;
+ }
+ return isolate->ThrowIllegalOperation();
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
+ NoHandleAllocation ha;
+ RUNTIME_ASSERT(args.length() == 1);
+ Handle<Object> object = args.at<Object>(0);
+ return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
+ NoHandleAllocation ha;
+ RUNTIME_ASSERT(args.length() == 1);
+ Handle<Object> object = args.at<Object>(0);
+ return TransitionElements(object, FAST_ELEMENTS, isolate);
+}
+
+
// Set the native flag on the function.
// This is used to decide if we should transform null and undefined
// into the global object when doing call and apply.
@@ -4751,8 +4825,11 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSObject, object, 0);
- return *GetKeysFor(object);
+ CONVERT_ARG_CHECKED(JSReceiver, object, 0);
+ bool threw = false;
+ Handle<JSArray> result = GetKeysFor(object, &threw);
+ if (threw) return Failure::Exception();
+ return *result;
}
@@ -4764,14 +4841,16 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
ASSERT(args.length() == 1);
- CONVERT_CHECKED(JSObject, raw_object, args[0]);
+ CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
if (raw_object->IsSimpleEnum()) return raw_object->map();
HandleScope scope(isolate);
- Handle<JSObject> object(raw_object);
- Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
- INCLUDE_PROTOS);
+ Handle<JSReceiver> object(raw_object);
+ bool threw = false;
+ Handle<FixedArray> content =
+ GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
+ if (threw) return Failure::Exception();
// Test again, since cache may have been built by preceding call.
if (object->IsSimpleEnum()) return object->map();
@@ -4968,8 +5047,11 @@
object = Handle<JSObject>::cast(proto);
}
- Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
- LOCAL_ONLY);
+ bool threw = false;
+ Handle<FixedArray> contents =
+ GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
+ if (threw) return Failure::Exception();
+
// Some fast paths through GetKeysInFixedArrayFor reuse a cached
// property array and since the result is mutable we have to create
// a fresh clone on each invocation.
@@ -7762,14 +7844,21 @@
int year, month, day;
DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
- RUNTIME_ASSERT(res_array->elements()->map() ==
- isolate->heap()->fixed_array_map());
- FixedArray* elms = FixedArray::cast(res_array->elements());
- RUNTIME_ASSERT(elms->length() == 3);
+ FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
+ RUNTIME_ASSERT(elms_base->length() == 3);
+ RUNTIME_ASSERT(res_array->GetElementsKind() <= FAST_DOUBLE_ELEMENTS);
- elms->set(0, Smi::FromInt(year));
- elms->set(1, Smi::FromInt(month));
- elms->set(2, Smi::FromInt(day));
+ if (res_array->HasFastDoubleElements()) {
+ FixedDoubleArray* elms = FixedDoubleArray::cast(res_array->elements());
+ elms->set(0, year);
+ elms->set(1, month);
+ elms->set(2, day);
+ } else {
+ FixedArray* elms = FixedArray::cast(res_array->elements());
+ elms->set(0, Smi::FromInt(year));
+ elms->set(1, Smi::FromInt(month));
+ elms->set(2, Smi::FromInt(day));
+ }
return isolate->heap()->undefined_value();
}
@@ -7926,8 +8015,11 @@
}
-static SmartArrayPointer<Handle<Object> > GetNonBoundArguments(
- int bound_argc,
+// Find the arguments of the JavaScript function invocation that called
+// into C++ code. Collect these in a newly allocated array of handles (possibly
+// prefixed by a number of empty handles).
+static SmartArrayPointer<Handle<Object> > GetCallerArguments(
+ int prefix_argc,
int* total_argc) {
// Find frame containing arguments passed to the caller.
JavaScriptFrameIterator it;
@@ -7943,12 +8035,12 @@
inlined_frame_index,
&args_slots);
- *total_argc = bound_argc + args_count;
+ *total_argc = prefix_argc + args_count;
SmartArrayPointer<Handle<Object> > param_data(
NewArray<Handle<Object> >(*total_argc));
for (int i = 0; i < args_count; i++) {
Handle<Object> val = args_slots[i].GetValue();
- param_data[bound_argc + i] = val;
+ param_data[prefix_argc + i] = val;
}
return param_data;
} else {
@@ -7956,49 +8048,131 @@
frame = it.frame();
int args_count = frame->ComputeParametersCount();
- *total_argc = bound_argc + args_count;
+ *total_argc = prefix_argc + args_count;
SmartArrayPointer<Handle<Object> > param_data(
NewArray<Handle<Object> >(*total_argc));
for (int i = 0; i < args_count; i++) {
Handle<Object> val = Handle<Object>(frame->GetParameter(i));
- param_data[bound_argc + i] = val;
+ param_data[prefix_argc + i] = val;
}
return param_data;
}
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 4);
+ CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
+ RUNTIME_ASSERT(args[3]->IsNumber());
+ Handle<Object> bindee = args.at<Object>(1);
+
+ // TODO(lrn): Create bound function in C++ code from premade shared info.
+ bound_function->shared()->set_bound(true);
+ // Get all arguments of calling function (Function.prototype.bind).
+ int argc = 0;
+ SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
+ // Don't count the this-arg.
+ if (argc > 0) {
+ ASSERT(*arguments[0] == args[2]);
+ argc--;
+ } else {
+ ASSERT(args[2]->IsUndefined());
+ }
+ // Initialize array of bindings (function, this, and any existing arguments
+ // if the function was already bound).
+ Handle<FixedArray> new_bindings;
+ int i;
+ if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
+ Handle<FixedArray> old_bindings(
+ JSFunction::cast(*bindee)->function_bindings());
+ new_bindings =
+ isolate->factory()->NewFixedArray(old_bindings->length() + argc);
+ bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
+ i = 0;
+ for (int n = old_bindings->length(); i < n; i++) {
+ new_bindings->set(i, old_bindings->get(i));
+ }
+ } else {
+ int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
+ new_bindings = isolate->factory()->NewFixedArray(array_size);
+ new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
+ new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
+ i = 2;
+ }
+ // Copy arguments, skipping the first which is "this_arg".
+ for (int j = 0; j < argc; j++, i++) {
+ new_bindings->set(i, *arguments[j + 1]);
+ }
+ new_bindings->set_map(isolate->heap()->fixed_cow_array_map());
+ bound_function->set_function_bindings(*new_bindings);
+
+ // Update length.
+ Handle<String> length_symbol = isolate->factory()->length_symbol();
+ Handle<Object> new_length(args.at<Object>(3));
+ PropertyAttributes attr =
+ static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
+ ForceSetProperty(bound_function, length_symbol, new_length, attr);
+ return *bound_function;
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
+ HandleScope handles(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(JSObject, callable, 0);
+ if (callable->IsJSFunction()) {
+ Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
+ if (function->shared()->bound()) {
+ Handle<FixedArray> bindings(function->function_bindings());
+ ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
+ return *isolate->factory()->NewJSArrayWithElements(bindings);
+ }
+ }
+ return isolate->heap()->undefined_value();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
HandleScope scope(isolate);
- ASSERT(args.length() == 2);
+ ASSERT(args.length() == 1);
// First argument is a function to use as a constructor.
CONVERT_ARG_CHECKED(JSFunction, function, 0);
+ RUNTIME_ASSERT(function->shared()->bound());
- // Second argument is either null or an array of bound arguments.
- Handle<FixedArray> bound_args;
- int bound_argc = 0;
- if (!args[1]->IsNull()) {
- CONVERT_ARG_CHECKED(JSArray, params, 1);
- RUNTIME_ASSERT(params->HasFastTypeElements());
- bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
- bound_argc = Smi::cast(params->length())->value();
- }
+ // The argument is a bound function. Extract its bound arguments
+ // and callable.
+ Handle<FixedArray> bound_args =
+ Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
+ int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
+ Handle<Object> bound_function(
+ JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
+ ASSERT(!bound_function->IsJSFunction() ||
+ !Handle<JSFunction>::cast(bound_function)->shared()->bound());
int total_argc = 0;
SmartArrayPointer<Handle<Object> > param_data =
- GetNonBoundArguments(bound_argc, &total_argc);
+ GetCallerArguments(bound_argc, &total_argc);
for (int i = 0; i < bound_argc; i++) {
- Handle<Object> val = Handle<Object>(bound_args->get(i));
- param_data[i] = val;
+ param_data[i] = Handle<Object>(bound_args->get(
+ JSFunction::kBoundArgumentsStartIndex + i));
}
+ if (!bound_function->IsJSFunction()) {
+ bool exception_thrown;
+ bound_function = Execution::TryGetConstructorDelegate(bound_function,
+ &exception_thrown);
+ if (exception_thrown) return Failure::Exception();
+ }
+ ASSERT(bound_function->IsJSFunction());
+
bool exception = false;
Handle<Object> result =
- Execution::New(function, total_argc, *param_data, &exception);
+ Execution::New(Handle<JSFunction>::cast(bound_function),
+ total_argc, *param_data, &exception);
if (exception) {
- return Failure::Exception();
+ return Failure::Exception();
}
-
ASSERT(!result.is_null());
return *result;
}
@@ -8011,7 +8185,8 @@
prototype = Handle<Object>(function->instance_prototype(), isolate);
}
if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
- ConstructStubCompiler compiler;
+ HandleScope scope(isolate);
+ ConstructStubCompiler compiler(isolate);
MaybeObject* code = compiler.CompileConstructStub(*function);
if (!code->IsFailure()) {
function->shared()->set_construct_stub(
@@ -8075,9 +8250,11 @@
// available. We cannot use EnsureCompiled because that forces a
// compilation through the shared function info which makes it
// impossible for us to optimize.
+ if (!function->is_compiled()) {
+ JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
+ }
+
Handle<SharedFunctionInfo> shared(function->shared(), isolate);
- if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
-
if (!function->has_initial_map() &&
shared->IsInobjectSlackTrackingInProgress()) {
// The tracking is already in progress for another function. We can only
@@ -8128,7 +8305,7 @@
// Compile the target function.
ASSERT(!function->is_compiled());
- if (!CompileLazy(function, KEEP_EXCEPTION)) {
+ if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
return Failure::Exception();
}
@@ -8165,7 +8342,9 @@
function->ReplaceCode(function->shared()->code());
return function->code();
}
- if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
+ if (JSFunction::CompileOptimized(function,
+ AstNode::kNoNumber,
+ CLEAR_EXCEPTION)) {
return function->code();
}
if (FLAG_trace_opt) {
@@ -8406,7 +8585,7 @@
// Try to compile the optimized code. A true return value from
// CompileOptimized means that compilation succeeded, not necessarily
// that optimization succeeded.
- if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
+ if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
function->IsOptimized()) {
DeoptimizationInputData* data = DeoptimizationInputData::cast(
function->code()->deoptimization_data());
@@ -8762,13 +8941,26 @@
Handle<Object> receiver = isolate->factory()->the_hole_value();
Object* value = Context::cast(*holder)->get(index);
// Check for uninitialized bindings.
- if (binding_flags == MUTABLE_CHECK_INITIALIZED && value->IsTheHole()) {
- Handle<Object> reference_error =
- isolate->factory()->NewReferenceError("not_defined",
- HandleVector(&name, 1));
- return MakePair(isolate->Throw(*reference_error), NULL);
- } else {
- return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
+ switch (binding_flags) {
+ case MUTABLE_CHECK_INITIALIZED:
+ case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
+ if (value->IsTheHole()) {
+ Handle<Object> reference_error =
+ isolate->factory()->NewReferenceError("not_defined",
+ HandleVector(&name, 1));
+ return MakePair(isolate->Throw(*reference_error), NULL);
+ }
+ // FALLTHROUGH
+ case MUTABLE_IS_INITIALIZED:
+ case IMMUTABLE_IS_INITIALIZED:
+ case IMMUTABLE_IS_INITIALIZED_HARMONY:
+ ASSERT(!value->IsTheHole());
+ return MakePair(value, *receiver);
+ case IMMUTABLE_CHECK_INITIALIZED:
+ return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
+ case MISSING_BINDING:
+ UNREACHABLE();
+ return MakePair(NULL, NULL);
}
}
@@ -8947,42 +9139,6 @@
}
-// NOTE: These PrintXXX functions are defined for all builds (not just
-// DEBUG builds) because we may want to be able to trace function
-// calls in all modes.
-static void PrintString(String* str) {
- // not uncommon to have empty strings
- if (str->length() > 0) {
- SmartArrayPointer<char> s =
- str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
- PrintF("%s", *s);
- }
-}
-
-
-static void PrintObject(Object* obj) {
- if (obj->IsSmi()) {
- PrintF("%d", Smi::cast(obj)->value());
- } else if (obj->IsString() || obj->IsSymbol()) {
- PrintString(String::cast(obj));
- } else if (obj->IsNumber()) {
- PrintF("%g", obj->Number());
- } else if (obj->IsFailure()) {
- PrintF("<failure>");
- } else if (obj->IsUndefined()) {
- PrintF("<undefined>");
- } else if (obj->IsNull()) {
- PrintF("<null>");
- } else if (obj->IsTrue()) {
- PrintF("<true>");
- } else if (obj->IsFalse()) {
- PrintF("<false>");
- } else {
- PrintF("%p", reinterpret_cast<void*>(obj));
- }
-}
-
-
static int StackSize() {
int n = 0;
for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
@@ -9001,38 +9157,33 @@
}
if (result == NULL) {
- // constructor calls
- JavaScriptFrameIterator it;
- JavaScriptFrame* frame = it.frame();
- if (frame->IsConstructor()) PrintF("new ");
- // function name
- Object* fun = frame->function();
- if (fun->IsJSFunction()) {
- PrintObject(JSFunction::cast(fun)->shared()->name());
- } else {
- PrintObject(fun);
- }
- // function arguments
- // (we are intentionally only printing the actually
- // supplied parameters, not all parameters required)
- PrintF("(this=");
- PrintObject(frame->receiver());
- const int length = frame->ComputeParametersCount();
- for (int i = 0; i < length; i++) {
- PrintF(", ");
- PrintObject(frame->GetParameter(i));
- }
- PrintF(") {\n");
-
+ JavaScriptFrame::PrintTop(stdout, true, false);
+ PrintF(" {\n");
} else {
// function result
PrintF("} -> ");
- PrintObject(result);
+ result->ShortPrint();
PrintF("\n");
}
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceElementsKindTransition) {
+ ASSERT(args.length() == 5);
+ CONVERT_ARG_CHECKED(JSObject, obj, 0);
+ CONVERT_SMI_ARG_CHECKED(from_kind, 1);
+ CONVERT_ARG_CHECKED(FixedArrayBase, from_elements, 2);
+ CONVERT_SMI_ARG_CHECKED(to_kind, 3);
+ CONVERT_ARG_CHECKED(FixedArrayBase, to_elements, 4);
+ NoHandleAllocation ha;
+ PrintF("*");
+ obj->PrintElementsTransition(stdout,
+ static_cast<ElementsKind>(from_kind), *from_elements,
+ static_cast<ElementsKind>(to_kind), *to_elements);
+ return isolate->heap()->undefined_value();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
ASSERT(args.length() == 0);
NoHandleAllocation ha;
@@ -9781,8 +9932,8 @@
} else if (receiver->HasElement(j)) {
// Call GetElement on receiver, not its prototype, or getters won't
// have the correct receiver.
- element_value = GetElement(receiver, j);
- if (element_value.is_null()) return false;
+ element_value = Object::GetElement(receiver, j);
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
visitor->visit(j, element_value);
}
}
@@ -9800,8 +9951,8 @@
while (j < n) {
HandleScope loop_scope;
uint32_t index = indices[j];
- Handle<Object> element = GetElement(receiver, index);
- if (element.is_null()) return false;
+ Handle<Object> element = Object::GetElement(receiver, index);
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
visitor->visit(index, element);
// Skip to next different index (i.e., omit duplicates).
do {
@@ -10051,9 +10202,9 @@
}
Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
- Handle<Object> tmp1 = GetElement(jsobject, index1);
+ Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
- Handle<Object> tmp2 = GetElement(jsobject, index2);
+ Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
RETURN_IF_EMPTY_HANDLE(isolate,
@@ -10078,7 +10229,11 @@
if (array->elements()->IsDictionary()) {
// Create an array and get all the keys into it, then remove all the
// keys that are not integers in the range 0 to length-1.
- Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
+ bool threw = false;
+ Handle<FixedArray> keys =
+ GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
+ if (threw) return Failure::Exception();
+
int keys_length = keys->length();
for (int i = 0; i < keys_length; i++) {
Object* key = keys->get(i);
@@ -10303,7 +10458,7 @@
// Try local lookup on each of the objects.
Handle<JSObject> jsproto = obj;
for (int i = 0; i < length; i++) {
- LookupResult result;
+ LookupResult result(isolate);
jsproto->LocalLookup(*name, &result);
if (result.IsProperty()) {
// LookupResult is not GC safe as it holds raw object pointers.
@@ -10360,7 +10515,7 @@
CONVERT_ARG_CHECKED(JSObject, obj, 0);
CONVERT_ARG_CHECKED(String, name, 1);
- LookupResult result;
+ LookupResult result(isolate);
obj->Lookup(*name, &result);
if (result.IsProperty()) {
return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
@@ -10897,7 +11052,11 @@
if (function_context->has_extension() &&
!function_context->IsGlobalContext()) {
Handle<JSObject> ext(JSObject::cast(function_context->extension()));
- Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
+ bool threw = false;
+ Handle<FixedArray> keys =
+ GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
+ if (threw) return Handle<JSObject>();
+
for (int i = 0; i < keys->length(); i++) {
// Names of variables introduced by eval are strings.
ASSERT(keys->get(i)->IsString());
@@ -10945,7 +11104,11 @@
// be variables introduced by eval.
if (context->has_extension()) {
Handle<JSObject> ext(JSObject::cast(context->extension()));
- Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
+ bool threw = false;
+ Handle<FixedArray> keys =
+ GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
+ if (threw) return Handle<JSObject>();
+
for (int i = 0; i < keys->length(); i++) {
// Names of variables introduced by eval are strings.
ASSERT(keys->get(i)->IsString());
@@ -11010,9 +11173,10 @@
}
-// Iterate over the actual scopes visible from a stack frame. All scopes are
+// Iterate over the actual scopes visible from a stack frame. The iteration
+// proceeds from the innermost visible nested scope outwards. All scopes are
// backed by an actual context except the local scope, which is inserted
-// "artifically" in the context chain.
+// "artificially" in the context chain.
class ScopeIterator {
public:
enum ScopeType {
@@ -11032,28 +11196,52 @@
inlined_frame_index_(inlined_frame_index),
function_(JSFunction::cast(frame->function())),
context_(Context::cast(frame->context())),
- local_done_(false),
- at_local_(false) {
+ nested_scope_chain_(4) {
- // Check whether the first scope is actually a local scope.
- // If there is a stack slot for .result then this local scope has been
- // created for evaluating top level code and it is not a real local scope.
+ // Catch the case when the debugger stops in an internal function.
+ Handle<SharedFunctionInfo> shared_info(function_->shared());
+ if (shared_info->script() == isolate->heap()->undefined_value()) {
+ while (context_->closure() == *function_) {
+ context_ = Handle<Context>(context_->previous(), isolate_);
+ }
+ return;
+ }
+
+ // Check whether we are in global code or function code. If there is a stack
+ // slot for .result then this function has been created for evaluating
+ // global code and it is not a real function.
// Checking for the existence of .result seems fragile, but the scope info
// saved with the code object does not otherwise have that information.
- int index = function_->shared()->scope_info()->
+ int index = shared_info->scope_info()->
StackSlotIndex(isolate_->heap()->result_symbol());
+
+ // Reparse the code and analyze the scopes.
+ ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
+ Handle<Script> script(Script::cast(shared_info->script()));
+ Scope* scope;
if (index >= 0) {
- local_done_ = true;
- } else if (context_->IsGlobalContext() ||
- context_->IsFunctionContext()) {
- at_local_ = true;
- } else if (context_->closure() != *function_) {
- // The context_ is a block or with or catch block from the outer function.
- ASSERT(context_->IsWithContext() ||
- context_->IsCatchContext() ||
- context_->IsBlockContext());
- at_local_ = true;
+ // Global code
+ CompilationInfo info(script);
+ info.MarkAsGlobal();
+ bool result = ParserApi::Parse(&info);
+ ASSERT(result);
+ result = Scope::Analyze(&info);
+ ASSERT(result);
+ scope = info.function()->scope();
+ } else {
+ // Function code
+ CompilationInfo info(shared_info);
+ bool result = ParserApi::Parse(&info);
+ ASSERT(result);
+ result = Scope::Analyze(&info);
+ ASSERT(result);
+ scope = info.function()->scope();
}
+
+ // Retrieve the scope chain for the current position.
+ int statement_position =
+ shared_info->code()->SourceStatementPosition(frame_->pc());
+ scope->GetNestedScopeChain(&nested_scope_chain_, statement_position);
}
// More scopes?
@@ -11061,40 +11249,48 @@
// Move to the next scope.
void Next() {
- // If at a local scope mark the local scope as passed.
- if (at_local_) {
- at_local_ = false;
- local_done_ = true;
-
- // If the current context is not associated with the local scope the
- // current context is the next real scope, so don't move to the next
- // context in this case.
- if (context_->closure() != *function_) {
- return;
- }
- }
-
- // The global scope is always the last in the chain.
- if (context_->IsGlobalContext()) {
+ ScopeType scope_type = Type();
+ if (scope_type == ScopeTypeGlobal) {
+ // The global scope is always the last in the chain.
+ ASSERT(context_->IsGlobalContext());
context_ = Handle<Context>();
return;
}
-
- // Move to the next context.
- context_ = Handle<Context>(context_->previous(), isolate_);
-
- // If passing the local scope indicate that the current scope is now the
- // local scope.
- if (!local_done_ &&
- (context_->IsGlobalContext() || context_->IsFunctionContext())) {
- at_local_ = true;
+ if (nested_scope_chain_.is_empty()) {
+ context_ = Handle<Context>(context_->previous(), isolate_);
+ } else {
+ if (nested_scope_chain_.last()->HasContext()) {
+ context_ = Handle<Context>(context_->previous(), isolate_);
+ }
+ nested_scope_chain_.RemoveLast();
}
}
// Return the type of the current scope.
ScopeType Type() {
- if (at_local_) {
- return ScopeTypeLocal;
+ if (!nested_scope_chain_.is_empty()) {
+ Handle<SerializedScopeInfo> scope_info = nested_scope_chain_.last();
+ switch (scope_info->Type()) {
+ case FUNCTION_SCOPE:
+ ASSERT(context_->IsFunctionContext() ||
+ !scope_info->HasContext());
+ return ScopeTypeLocal;
+ case GLOBAL_SCOPE:
+ ASSERT(context_->IsGlobalContext());
+ return ScopeTypeGlobal;
+ case WITH_SCOPE:
+ ASSERT(context_->IsWithContext());
+ return ScopeTypeWith;
+ case CATCH_SCOPE:
+ ASSERT(context_->IsCatchContext());
+ return ScopeTypeCatch;
+ case BLOCK_SCOPE:
+ ASSERT(!scope_info->HasContext() ||
+ context_->IsBlockContext());
+ return ScopeTypeBlock;
+ case EVAL_SCOPE:
+ UNREACHABLE();
+ }
}
if (context_->IsGlobalContext()) {
ASSERT(context_->global()->IsGlobalObject());
@@ -11120,6 +11316,7 @@
return Handle<JSObject>(CurrentContext()->global());
case ScopeIterator::ScopeTypeLocal:
// Materialize the content of the local scope into a JSObject.
+ ASSERT(nested_scope_chain_.length() == 1);
return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
case ScopeIterator::ScopeTypeWith:
// Return the with object.
@@ -11136,13 +11333,30 @@
return Handle<JSObject>();
}
+ Handle<SerializedScopeInfo> CurrentScopeInfo() {
+ if (!nested_scope_chain_.is_empty()) {
+ return nested_scope_chain_.last();
+ } else if (context_->IsBlockContext()) {
+ return Handle<SerializedScopeInfo>(
+ SerializedScopeInfo::cast(context_->extension()));
+ } else if (context_->IsFunctionContext()) {
+ return Handle<SerializedScopeInfo>(
+ context_->closure()->shared()->scope_info());
+ }
+ return Handle<SerializedScopeInfo>::null();
+ }
+
// Return the context for this scope. For the local context there might not
// be an actual context.
Handle<Context> CurrentContext() {
- if (at_local_ && context_->closure() != *function_) {
+ if (Type() == ScopeTypeGlobal ||
+ nested_scope_chain_.is_empty()) {
+ return context_;
+ } else if (nested_scope_chain_.last()->HasContext()) {
+ return context_;
+ } else {
return Handle<Context>();
}
- return context_;
}
#ifdef DEBUG
@@ -11205,8 +11419,7 @@
int inlined_frame_index_;
Handle<JSFunction> function_;
Handle<Context> context_;
- bool local_done_;
- bool at_local_;
+ List<Handle<SerializedScopeInfo> > nested_scope_chain_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
};
@@ -11521,7 +11734,7 @@
if (!done) {
// If the candidate is not compiled compile it to reveal any inner
// functions which might contain the requested source position.
- CompileLazyShared(target, KEEP_EXCEPTION);
+ SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
}
} // End while loop.
@@ -11669,46 +11882,65 @@
// Creates a copy of the with context chain. The copy of the context chain is
// is linked to the function context supplied.
-static Handle<Context> CopyWithContextChain(Isolate* isolate,
- Handle<JSFunction> function,
- Handle<Context> current,
- Handle<Context> base) {
- // At the end of the chain. Return the base context to link to.
- if (current->IsFunctionContext() || current->IsGlobalContext()) {
- return base;
+static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
+ Handle<JSFunction> function,
+ Handle<Context> base,
+ JavaScriptFrame* frame,
+ int inlined_frame_index) {
+ HandleScope scope(isolate);
+ List<Handle<SerializedScopeInfo> > scope_chain;
+ List<Handle<Context> > context_chain;
+
+ ScopeIterator it(isolate, frame, inlined_frame_index);
+ for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
+ it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
+ ASSERT(!it.Done());
+ scope_chain.Add(it.CurrentScopeInfo());
+ context_chain.Add(it.CurrentContext());
}
- // Recursively copy the with and catch contexts.
- HandleScope scope(isolate);
- Handle<Context> previous(current->previous());
- Handle<Context> new_previous =
- CopyWithContextChain(isolate, function, previous, base);
- Handle<Context> new_current;
- if (current->IsCatchContext()) {
- Handle<String> name(String::cast(current->extension()));
- Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
- new_current =
- isolate->factory()->NewCatchContext(function,
- new_previous,
- name,
- thrown_object);
- } else if (current->IsBlockContext()) {
- Handle<SerializedScopeInfo> scope_info(
- SerializedScopeInfo::cast(current->extension()));
- new_current =
- isolate->factory()->NewBlockContext(function, new_previous, scope_info);
- // Copy context slots.
- int num_context_slots = scope_info->NumberOfContextSlots();
- for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
- new_current->set(i, current->get(i));
+ // At the end of the chain. Return the base context to link to.
+ Handle<Context> context = base;
+
+ // Iteratively copy and or materialize the nested contexts.
+ while (!scope_chain.is_empty()) {
+ Handle<SerializedScopeInfo> scope_info = scope_chain.RemoveLast();
+ Handle<Context> current = context_chain.RemoveLast();
+ ASSERT(!(scope_info->HasContext() & current.is_null()));
+
+ if (scope_info->Type() == CATCH_SCOPE) {
+ Handle<String> name(String::cast(current->extension()));
+ Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
+ context =
+ isolate->factory()->NewCatchContext(function,
+ context,
+ name,
+ thrown_object);
+ } else if (scope_info->Type() == BLOCK_SCOPE) {
+ // Materialize the contents of the block scope into a JSObject.
+ Handle<JSObject> block_scope_object =
+ MaterializeBlockScope(isolate, current);
+ if (block_scope_object.is_null()) {
+ return Handle<Context>::null();
+ }
+ // Allocate a new function context for the debug evaluation and set the
+ // extension object.
+ Handle<Context> new_context =
+ isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
+ function);
+ new_context->set_extension(*block_scope_object);
+ new_context->set_previous(*context);
+ context = new_context;
+ } else {
+ ASSERT(scope_info->Type() == WITH_SCOPE);
+ ASSERT(current->IsWithContext());
+ Handle<JSObject> extension(JSObject::cast(current->extension()));
+ context =
+ isolate->factory()->NewWithContext(function, context, extension);
}
- } else {
- ASSERT(current->IsWithContext());
- Handle<JSObject> extension(JSObject::cast(current->extension()));
- new_current =
- isolate->factory()->NewWithContext(function, new_previous, extension);
}
- return scope.CloseAndEscape(new_current);
+
+ return scope.CloseAndEscape(context);
}
@@ -11846,7 +12078,11 @@
if (scope_info->HasHeapAllocatedLocals()) {
function_context = Handle<Context>(frame_context->declaration_context());
}
- context = CopyWithContextChain(isolate, go_between, frame_context, context);
+ context = CopyNestedScopeContextChain(isolate,
+ go_between,
+ context,
+ frame,
+ inlined_frame_index);
if (additional_context->IsJSObject()) {
Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
@@ -12245,7 +12481,7 @@
// Get the function and make sure it is compiled.
CONVERT_ARG_CHECKED(JSFunction, func, 0);
Handle<SharedFunctionInfo> shared(func->shared());
- if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
+ if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
return Failure::Exception();
}
func->code()->PrintLn();
@@ -12261,7 +12497,7 @@
// Get the function and make sure it is compiled.
CONVERT_ARG_CHECKED(JSFunction, func, 0);
Handle<SharedFunctionInfo> shared(func->shared());
- if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
+ if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
return Failure::Exception();
}
shared->construct_stub()->PrintLn();
@@ -12867,35 +13103,33 @@
Object* caller,
bool* seen_caller) {
// Only display JS frames.
- if (!raw_frame->is_java_script())
+ if (!raw_frame->is_java_script()) {
return false;
+ }
JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
Object* raw_fun = frame->function();
// Not sure when this can happen but skip it just in case.
- if (!raw_fun->IsJSFunction())
+ if (!raw_fun->IsJSFunction()) {
return false;
+ }
if ((raw_fun == caller) && !(*seen_caller)) {
*seen_caller = true;
return false;
}
// Skip all frames until we've seen the caller.
if (!(*seen_caller)) return false;
- // Also, skip the most obvious builtin calls. We recognize builtins
- // as (1) functions called with the builtins object as the receiver and
- // as (2) functions from native scripts called with undefined as the
- // receiver (direct calls to helper functions in the builtins
- // code). Some builtin calls (such as Number.ADD which is invoked
- // using 'call') are very difficult to recognize so we're leaving
- // them in for now.
- if (frame->receiver()->IsJSBuiltinsObject()) {
- return false;
+ // Also, skip non-visible built-in functions and any call with the builtins
+ // object as receiver, so as to not reveal either the builtins object or
+ // an internal function.
+ // The --builtins-in-stack-traces command line flag allows including
+ // internal call sites in the stack trace for debugging purposes.
+ if (!FLAG_builtins_in_stack_traces) {
+ JSFunction* fun = JSFunction::cast(raw_fun);
+ if (frame->receiver()->IsJSBuiltinsObject() ||
+ (fun->IsBuiltin() && !fun->shared()->native())) {
+ return false;
+ }
}
- JSFunction* fun = JSFunction::cast(raw_fun);
- Object* raw_script = fun->shared()->script();
- if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
- int script_type = Script::cast(raw_script)->type()->value();
- return script_type != Script::TYPE_NATIVE;
- }
return true;
}
@@ -13041,7 +13275,9 @@
}
#ifdef DEBUG
- cache_handle->JSFunctionResultCacheVerify();
+ if (FLAG_verify_heap) {
+ cache_handle->JSFunctionResultCacheVerify();
+ }
#endif
// Function invocation may have cleared the cache. Reread all the data.
@@ -13070,7 +13306,9 @@
cache_handle->set_finger_index(index);
#ifdef DEBUG
- cache_handle->JSFunctionResultCacheVerify();
+ if (FLAG_verify_heap) {
+ cache_handle->JSFunctionResultCacheVerify();
+ }
#endif
return *value;
« no previous file with comments | « src/runtime.h ('k') | src/runtime.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698