Version 3.1.8.
Fixed a number of crash bugs.
Improved Crankshaft for x64 and ARM.
Implemented more of EcmaScript 5 strict mode.
Fixed issue with unaligned reads and writes on ARM.
Improved heap profiler support.
git-svn-id: http://v8.googlecode.com/svn/trunk@7023 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/runtime.cc b/src/runtime.cc
index dce2e15..0c15f60 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -40,8 +40,10 @@
#include "debug.h"
#include "deoptimizer.h"
#include "execution.h"
+#include "global-handles.h"
#include "jsregexp.h"
#include "liveedit.h"
+#include "liveobjectlist-inl.h"
#include "parser.h"
#include "platform.h"
#include "runtime.h"
@@ -160,7 +162,8 @@
if (!maybe_result->ToObject(&result)) return maybe_result;
}
{ MaybeObject* maybe_result =
- copy->SetProperty(key_string, result, NONE);
+ // Creating object copy for literals. No strict mode needed.
+ copy->SetProperty(key_string, result, NONE, kNonStrictMode);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
}
@@ -546,7 +549,9 @@
// Assign the exception value to the catch variable and make sure
// that the catch variable is DontDelete.
{ MaybeObject* maybe_value =
- JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
+ // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
+ JSObject::cast(object)->SetProperty(
+ key, value, DONT_DELETE, kNonStrictMode);
if (!maybe_value->ToObject(&value)) return maybe_value;
}
return object;
@@ -783,7 +788,8 @@
case JSObject::INTERCEPTED_ELEMENT:
case JSObject::FAST_ELEMENT: {
elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
- elms->set(VALUE_INDEX, *GetElement(obj, index));
+ Handle<Object> value = GetElement(obj, index);
+ elms->set(VALUE_INDEX, *value);
elms->set(WRITABLE_INDEX, Heap::true_value());
elms->set(ENUMERABLE_INDEX, Heap::true_value());
elms->set(CONFIGURABLE_INDEX, Heap::true_value());
@@ -816,12 +822,14 @@
}
break;
}
- case NORMAL:
+ case NORMAL: {
// This is a data property.
elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
- elms->set(VALUE_INDEX, *GetElement(obj, index));
+ Handle<Object> value = GetElement(obj, index);
+ elms->set(VALUE_INDEX, *value);
elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
break;
+ }
default:
UNREACHABLE();
break;
@@ -994,12 +1002,16 @@
static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
+ ASSERT(args.length() == 4);
HandleScope scope;
Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
Handle<Context> context = args.at<Context>(0);
CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
bool is_eval = Smi::cast(args[2])->value() == 1;
+ StrictModeFlag strict_mode =
+ static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
+ ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
// Compute the property attributes. According to ECMA-262, section
// 13, page 71, the property must be read-only and
@@ -1104,12 +1116,21 @@
// onload setter in those case and Safari does not. We follow
// Safari for compatibility.
if (value->IsJSFunction()) {
+ // Do not change DONT_DELETE to false from true.
+ if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
+ attributes = static_cast<PropertyAttributes>(
+ attributes | (lookup.GetAttributes() & DONT_DELETE));
+ }
RETURN_IF_EMPTY_HANDLE(SetLocalPropertyIgnoreAttributes(global,
name,
value,
attributes));
} else {
- RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, attributes));
+ RETURN_IF_EMPTY_HANDLE(SetProperty(global,
+ name,
+ value,
+ attributes,
+ strict_mode));
}
}
@@ -1170,7 +1191,8 @@
// Slow case: The property is not in the FixedArray part of the context.
Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
RETURN_IF_EMPTY_HANDLE(
- SetProperty(context_ext, name, initial_value, mode));
+ SetProperty(context_ext, name, initial_value,
+ mode, kNonStrictMode));
}
}
@@ -1211,7 +1233,8 @@
return ThrowRedeclarationError("const", name);
}
}
- RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, mode));
+ RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, mode,
+ kNonStrictMode));
}
return Heap::undefined_value();
@@ -1220,14 +1243,21 @@
static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
NoHandleAllocation nha;
+ // args[0] == name
+ // args[1] == strict_mode
+ // args[2] == value (optional)
// Determine if we need to assign to the variable if it already
// exists (based on the number of arguments).
- RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
- bool assign = args.length() == 2;
+ RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
+ bool assign = args.length() == 3;
CONVERT_ARG_CHECKED(String, name, 0);
GlobalObject* global = Top::context()->global();
+ RUNTIME_ASSERT(args[1]->IsSmi());
+ StrictModeFlag strict_mode =
+ static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
+ ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
// According to ECMA-262, section 12.2, page 62, the property must
// not be deletable.
@@ -1283,8 +1313,9 @@
}
// Assign the value (or undefined) to the property.
- Object* value = (assign) ? args[1] : Heap::undefined_value();
- return real_holder->SetProperty(&lookup, *name, value, attributes);
+ Object* value = (assign) ? args[2] : Heap::undefined_value();
+ return real_holder->SetProperty(
+ &lookup, *name, value, attributes, strict_mode);
}
Object* proto = real_holder->GetPrototype();
@@ -1298,7 +1329,9 @@
}
global = Top::context()->global();
- if (assign) return global->SetProperty(*name, args[1], attributes);
+ if (assign) {
+ return global->SetProperty(*name, args[2], attributes, strict_mode);
+ }
return Heap::undefined_value();
}
@@ -1357,13 +1390,19 @@
// BUG 1213575: Handle the case where we have to set a read-only
// property through an interceptor and only do it if it's
// uninitialized, e.g. the hole. Nirk...
- RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, attributes));
+ // Passing non-strict mode because the property is writable.
+ RETURN_IF_EMPTY_HANDLE(SetProperty(global,
+ name,
+ value,
+ attributes,
+ kNonStrictMode));
return *value;
}
// Set the value, but only 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).
PropertyType type = lookup.type();
if (type == FIELD) {
FixedArray* properties = global->properties();
@@ -1439,7 +1478,9 @@
// context.
if (attributes == ABSENT) {
Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
- RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, NONE));
+ // Strict mode not needed (const disallowed in strict mode).
+ RETURN_IF_EMPTY_HANDLE(
+ SetProperty(global, name, value, NONE, kNonStrictMode));
return *value;
}
@@ -1476,8 +1517,9 @@
// 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) {
+ // Strict mode not needed (const disallowed in strict mode).
RETURN_IF_EMPTY_HANDLE(
- SetProperty(context_ext, name, value, attributes));
+ SetProperty(context_ext, name, value, attributes, kNonStrictMode));
}
}
@@ -1643,7 +1685,7 @@
code,
false);
optimized->shared()->DontAdaptArguments();
- SetProperty(holder, key, optimized, NONE);
+ SetProperty(holder, key, optimized, NONE, kStrictMode);
return optimized;
}
@@ -3739,7 +3781,8 @@
MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
Handle<Object> key,
Handle<Object> value,
- PropertyAttributes attr) {
+ PropertyAttributes attr,
+ StrictModeFlag strict) {
HandleScope scope;
if (object->IsUndefined() || object->IsNull()) {
@@ -3769,6 +3812,7 @@
return *value;
}
+ // TODO(1220): Implement SetElement strict mode.
Handle<Object> result = SetElement(js_object, index, value);
if (result.is_null()) return Failure::Exception();
return *value;
@@ -3781,7 +3825,7 @@
} else {
Handle<String> key_string = Handle<String>::cast(key);
key_string->TryFlatten();
- result = SetProperty(js_object, key_string, value, attr);
+ result = SetProperty(js_object, key_string, value, attr, strict);
}
if (result.is_null()) return Failure::Exception();
return *value;
@@ -3794,9 +3838,10 @@
Handle<String> name = Handle<String>::cast(converted);
if (name->AsArrayIndex(&index)) {
+ // TODO(1220): Implement SetElement strict mode.
return js_object->SetElement(index, *value);
} else {
- return js_object->SetProperty(*name, *value, attr);
+ return js_object->SetProperty(*name, *value, attr, strict);
}
}
@@ -3888,23 +3933,27 @@
static MaybeObject* Runtime_SetProperty(Arguments args) {
NoHandleAllocation ha;
- RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
+ RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
Handle<Object> object = args.at<Object>(0);
Handle<Object> key = args.at<Object>(1);
Handle<Object> value = args.at<Object>(2);
-
+ CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
+ RUNTIME_ASSERT(
+ (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
// Compute attributes.
- PropertyAttributes attributes = NONE;
- if (args.length() == 4) {
- CONVERT_CHECKED(Smi, value_obj, args[3]);
- int unchecked_value = value_obj->value();
- // Only attribute bits should be set.
- RUNTIME_ASSERT(
- (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
- attributes = static_cast<PropertyAttributes>(unchecked_value);
+ PropertyAttributes attributes =
+ static_cast<PropertyAttributes>(unchecked_attributes);
+
+ StrictModeFlag strict = kNonStrictMode;
+ if (args.length() == 5) {
+ CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
+ RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
+ strict_unchecked == kNonStrictMode);
+ strict = static_cast<StrictModeFlag>(strict_unchecked);
}
- return Runtime::SetObjectProperty(object, key, value, attributes);
+
+ return Runtime::SetObjectProperty(object, key, value, attributes, strict);
}
@@ -3938,7 +3987,7 @@
CONVERT_CHECKED(JSObject, object, args[0]);
CONVERT_CHECKED(String, key, args[1]);
CONVERT_SMI_CHECKED(strict, args[2]);
- return object->DeleteProperty(key, strict == kStrictMode
+ return object->DeleteProperty(key, (strict == kStrictMode)
? JSObject::STRICT_DELETION
: JSObject::NORMAL_DELETION);
}
@@ -7486,11 +7535,16 @@
static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
HandleScope scope;
- ASSERT(args.length() == 3);
+ ASSERT(args.length() == 4);
Handle<Object> value(args[0]);
CONVERT_ARG_CHECKED(Context, context, 1);
CONVERT_ARG_CHECKED(String, name, 2);
+ CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
+ RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
+ strict_unchecked == kNonStrictMode);
+ StrictModeFlag strict = static_cast<StrictModeFlag>(strict_unchecked);
+
int index;
PropertyAttributes attributes;
@@ -7534,7 +7588,12 @@
// extension object itself.
if ((attributes & READ_ONLY) == 0 ||
(context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
- RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, NONE));
+ RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, NONE, strict));
+ } else if (strict == kStrictMode && (attributes & READ_ONLY) != 0) {
+ // Setting read only property in strict mode.
+ Handle<Object> error =
+ Factory::NewTypeError("strict_cannot_assign", HandleVector(&name, 1));
+ return Top::Throw(*error);
}
return *value;
}
@@ -7863,12 +7922,9 @@
static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
ASSERT(args.length() == 4);
- if (!args[0]->IsJSFunction()) {
- return MakePair(Top::ThrowIllegalOperation(), NULL);
- }
HandleScope scope;
- Handle<JSFunction> callee = args.at<JSFunction>(0);
+ Handle<Object> callee = args.at<Object>(0);
Handle<Object> receiver; // Will be overwritten.
// Compute the calling context.
@@ -7936,12 +7992,9 @@
static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
ASSERT(args.length() == 4);
- if (!args[0]->IsJSFunction()) {
- return MakePair(Top::ThrowIllegalOperation(), NULL);
- }
HandleScope scope;
- Handle<JSFunction> callee = args.at<JSFunction>(0);
+ Handle<Object> callee = args.at<Object>(0);
// 'eval' is bound in the global context, but it may have been overwritten.
// Compare it to the builtin 'GlobalEval' function to make sure.
@@ -8033,10 +8086,14 @@
public:
ArrayConcatVisitor(Handle<FixedArray> storage,
bool fast_elements) :
- storage_(storage),
+ storage_(Handle<FixedArray>::cast(GlobalHandles::Create(*storage))),
index_offset_(0u),
fast_elements_(fast_elements) { }
+ ~ArrayConcatVisitor() {
+ clear_storage();
+ }
+
void visit(uint32_t i, Handle<Object> elm) {
if (i >= JSObject::kMaxElementCount - index_offset_) return;
uint32_t index = index_offset_ + i;
@@ -8054,11 +8111,13 @@
// Fall-through to dictionary mode.
}
ASSERT(!fast_elements_);
- Handle<NumberDictionary> dict(storage_.cast<NumberDictionary>());
+ Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
Handle<NumberDictionary> result =
Factory::DictionaryAtNumberPut(dict, index, elm);
if (!result.is_identical_to(dict)) {
- storage_ = Handle<FixedArray>::cast(result);
+ // Dictionary needed to grow.
+ clear_storage();
+ set_storage(*result);
}
}
@@ -8090,23 +8149,35 @@
// Convert storage to dictionary mode.
void SetDictionaryMode(uint32_t index) {
ASSERT(fast_elements_);
- Handle<FixedArray> current_storage(storage_.ToHandle());
- HandleCell<NumberDictionary> slow_storage(
+ Handle<FixedArray> current_storage(*storage_);
+ Handle<NumberDictionary> slow_storage(
Factory::NewNumberDictionary(current_storage->length()));
uint32_t current_length = static_cast<uint32_t>(current_storage->length());
for (uint32_t i = 0; i < current_length; i++) {
HandleScope loop_scope;
Handle<Object> element(current_storage->get(i));
if (!element->IsTheHole()) {
- slow_storage =
- Factory::DictionaryAtNumberPut(slow_storage.ToHandle(), i, element);
+ Handle<NumberDictionary> new_storage =
+ Factory::DictionaryAtNumberPut(slow_storage, i, element);
+ if (!new_storage.is_identical_to(slow_storage)) {
+ slow_storage = loop_scope.CloseAndEscape(new_storage);
+ }
}
}
- storage_ = slow_storage.cast<FixedArray>();
+ clear_storage();
+ set_storage(*slow_storage);
fast_elements_ = false;
}
- HandleCell<FixedArray> storage_;
+ inline void clear_storage() {
+ GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
+ }
+
+ inline void set_storage(FixedArray* storage) {
+ storage_ = Handle<FixedArray>::cast(GlobalHandles::Create(storage));
+ }
+
+ Handle<FixedArray> storage_; // Always a global handle.
// Index after last seen index. Always less than or equal to
// JSObject::kMaxElementCount.
uint32_t index_offset_;
@@ -9267,7 +9338,9 @@
RETURN_IF_EMPTY_HANDLE_VALUE(
SetProperty(scope_object,
scope_info.context_slot_name(i),
- Handle<Object>(context->get(context_index)), NONE),
+ Handle<Object>(context->get(context_index)),
+ NONE,
+ kNonStrictMode),
false);
}
}
@@ -9293,7 +9366,9 @@
RETURN_IF_EMPTY_HANDLE_VALUE(
SetProperty(local_scope,
scope_info.parameter_name(i),
- Handle<Object>(frame->GetParameter(i)), NONE),
+ Handle<Object>(frame->GetParameter(i)),
+ NONE,
+ kNonStrictMode),
Handle<JSObject>());
}
@@ -9302,7 +9377,9 @@
RETURN_IF_EMPTY_HANDLE_VALUE(
SetProperty(local_scope,
scope_info.stack_slot_name(i),
- Handle<Object>(frame->GetExpression(i)), NONE),
+ Handle<Object>(frame->GetExpression(i)),
+ NONE,
+ kNonStrictMode),
Handle<JSObject>());
}
@@ -9326,7 +9403,11 @@
ASSERT(keys->get(i)->IsString());
Handle<String> key(String::cast(keys->get(i)));
RETURN_IF_EMPTY_HANDLE_VALUE(
- SetProperty(local_scope, key, GetProperty(ext, key), NONE),
+ SetProperty(local_scope,
+ key,
+ GetProperty(ext, key),
+ NONE,
+ kNonStrictMode),
Handle<JSObject>());
}
}
@@ -9364,7 +9445,8 @@
SetProperty(closure_scope,
scope_info.parameter_name(i),
Handle<Object>(element),
- NONE),
+ NONE,
+ kNonStrictMode),
Handle<JSObject>());
}
}
@@ -9385,7 +9467,11 @@
ASSERT(keys->get(i)->IsString());
Handle<String> key(String::cast(keys->get(i)));
RETURN_IF_EMPTY_HANDLE_VALUE(
- SetProperty(closure_scope, key, GetProperty(ext, key), NONE),
+ SetProperty(closure_scope,
+ key,
+ GetProperty(ext, key),
+ NONE,
+ kNonStrictMode),
Handle<JSObject>());
}
}
@@ -10863,6 +10949,207 @@
}
return Smi::FromInt(usage);
}
+
+
+// Captures a live object list from the present heap.
+static MaybeObject* Runtime_HasLOLEnabled(Arguments args) {
+#ifdef LIVE_OBJECT_LIST
+ return Heap::true_value();
+#else
+ return Heap::false_value();
+#endif
+}
+
+
+// Captures a live object list from the present heap.
+static MaybeObject* Runtime_CaptureLOL(Arguments args) {
+#ifdef LIVE_OBJECT_LIST
+ return LiveObjectList::Capture();
+#else
+ return Heap::undefined_value();
+#endif
+}
+
+
+// Deletes the specified live object list.
+static MaybeObject* Runtime_DeleteLOL(Arguments args) {
+#ifdef LIVE_OBJECT_LIST
+ CONVERT_SMI_CHECKED(id, args[0]);
+ bool success = LiveObjectList::Delete(id);
+ return success ? Heap::true_value() : Heap::false_value();
+#else
+ return Heap::undefined_value();
+#endif
+}
+
+
+// Generates the response to a debugger request for a dump of the objects
+// contained in the difference between the captured live object lists
+// specified by id1 and id2.
+// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
+// dumped.
+static MaybeObject* Runtime_DumpLOL(Arguments args) {
+#ifdef LIVE_OBJECT_LIST
+ HandleScope scope;
+ CONVERT_SMI_CHECKED(id1, args[0]);
+ CONVERT_SMI_CHECKED(id2, args[1]);
+ CONVERT_SMI_CHECKED(start, args[2]);
+ CONVERT_SMI_CHECKED(count, args[3]);
+ CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
+ EnterDebugger enter_debugger;
+ return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
+#else
+ return Heap::undefined_value();
+#endif
+}
+
+
+// Gets the specified object as requested by the debugger.
+// This is only used for obj ids shown in live object lists.
+static MaybeObject* Runtime_GetLOLObj(Arguments args) {
+#ifdef LIVE_OBJECT_LIST
+ CONVERT_SMI_CHECKED(obj_id, args[0]);
+ Object* result = LiveObjectList::GetObj(obj_id);
+ return result;
+#else
+ return Heap::undefined_value();
+#endif
+}
+
+
+// Gets the obj id for the specified address if valid.
+// This is only used for obj ids shown in live object lists.
+static MaybeObject* Runtime_GetLOLObjId(Arguments args) {
+#ifdef LIVE_OBJECT_LIST
+ HandleScope scope;
+ CONVERT_ARG_CHECKED(String, address, 0);
+ Object* result = LiveObjectList::GetObjId(address);
+ return result;
+#else
+ return Heap::undefined_value();
+#endif
+}
+
+
+// Gets the retainers that references the specified object alive.
+static MaybeObject* Runtime_GetLOLObjRetainers(Arguments args) {
+#ifdef LIVE_OBJECT_LIST
+ HandleScope scope;
+ CONVERT_SMI_CHECKED(obj_id, args[0]);
+ RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
+ RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
+ RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
+ RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
+ CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
+
+ Handle<JSObject> instance_filter;
+ if (args[1]->IsJSObject()) {
+ instance_filter = args.at<JSObject>(1);
+ }
+ bool verbose = false;
+ if (args[2]->IsBoolean()) {
+ verbose = args[2]->IsTrue();
+ }
+ int start = 0;
+ if (args[3]->IsSmi()) {
+ start = Smi::cast(args[3])->value();
+ }
+ int limit = Smi::kMaxValue;
+ if (args[4]->IsSmi()) {
+ limit = Smi::cast(args[4])->value();
+ }
+
+ return LiveObjectList::GetObjRetainers(obj_id,
+ instance_filter,
+ verbose,
+ start,
+ limit,
+ filter_obj);
+#else
+ return Heap::undefined_value();
+#endif
+}
+
+
+// Gets the reference path between 2 objects.
+static MaybeObject* Runtime_GetLOLPath(Arguments args) {
+#ifdef LIVE_OBJECT_LIST
+ HandleScope scope;
+ CONVERT_SMI_CHECKED(obj_id1, args[0]);
+ CONVERT_SMI_CHECKED(obj_id2, args[1]);
+ RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
+
+ Handle<JSObject> instance_filter;
+ if (args[2]->IsJSObject()) {
+ instance_filter = args.at<JSObject>(2);
+ }
+
+ Object* result =
+ LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
+ return result;
+#else
+ return Heap::undefined_value();
+#endif
+}
+
+
+// Generates the response to a debugger request for a list of all
+// previously captured live object lists.
+static MaybeObject* Runtime_InfoLOL(Arguments args) {
+#ifdef LIVE_OBJECT_LIST
+ CONVERT_SMI_CHECKED(start, args[0]);
+ CONVERT_SMI_CHECKED(count, args[1]);
+ return LiveObjectList::Info(start, count);
+#else
+ return Heap::undefined_value();
+#endif
+}
+
+
+// Gets a dump of the specified object as requested by the debugger.
+// This is only used for obj ids shown in live object lists.
+static MaybeObject* Runtime_PrintLOLObj(Arguments args) {
+#ifdef LIVE_OBJECT_LIST
+ HandleScope scope;
+ CONVERT_SMI_CHECKED(obj_id, args[0]);
+ Object* result = LiveObjectList::PrintObj(obj_id);
+ return result;
+#else
+ return Heap::undefined_value();
+#endif
+}
+
+
+// Resets and releases all previously captured live object lists.
+static MaybeObject* Runtime_ResetLOL(Arguments args) {
+#ifdef LIVE_OBJECT_LIST
+ LiveObjectList::Reset();
+ return Heap::undefined_value();
+#else
+ return Heap::undefined_value();
+#endif
+}
+
+
+// Generates the response to a debugger request for a summary of the types
+// of objects in the difference between the captured live object lists
+// specified by id1 and id2.
+// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
+// summarized.
+static MaybeObject* Runtime_SummarizeLOL(Arguments args) {
+#ifdef LIVE_OBJECT_LIST
+ HandleScope scope;
+ CONVERT_SMI_CHECKED(id1, args[0]);
+ CONVERT_SMI_CHECKED(id2, args[1]);
+ CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
+
+ EnterDebugger enter_debugger;
+ return LiveObjectList::Summarize(id1, id2, filter_obj);
+#else
+ return Heap::undefined_value();
+#endif
+}
+
#endif // ENABLE_DEBUGGER_SUPPORT