Improved code generation infrastructure by doing simple register allocation and constant folding and propagation.
Optimized regular expression matching by avoiding to create intermediate string arrays and by flattening nested array representations of RegExp data.
Traverse a few stack frames when recording profiler samples to include partial call graphs in the profiling output.
Added support for using OProfile to profile generated code.
Added remote debugging support to the D8 developer shell.
Optimized creation of nested literals like JSON objects.
Fixed a bug in garbage collecting unused maps and turned it on by default (--collect-maps).
Added support for running tests under Valgrind.
git-svn-id: http://v8.googlecode.com/svn/trunk@1495 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/runtime.cc b/src/runtime.cc
index b04af51..bd81704 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -43,6 +43,7 @@
#include "scopeinfo.h"
#include "v8threads.h"
#include "smart-pointer.h"
+#include "parser.h"
namespace v8 { namespace internal {
@@ -69,6 +70,13 @@
RUNTIME_ASSERT(obj->IsBoolean()); \
bool name = (obj)->IsTrue();
+// Cast the given object to an int and store it in a variable with
+// the given name. If the object is not a Smi call IllegalOperation
+// and return.
+#define CONVERT_INT_CHECKED(name, obj) \
+ RUNTIME_ASSERT(obj->IsSmi()); \
+ int name = Smi::cast(obj)->value();
+
// Cast the given object to a double and store it in a variable with
// the given name. If the object is not a number (as opposed to
// the number not-a-number) call IllegalOperation and return.
@@ -84,7 +92,7 @@
type name = NumberTo##Type(obj);
// Non-reentrant string buffer for efficient general use in this file.
-static StaticResource<StringInputBuffer> string_input_buffer;
+static StaticResource<StringInputBuffer> runtime_string_input_buffer;
static Object* IllegalOperation() {
@@ -92,7 +100,7 @@
}
-static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
+static Object* Runtime_CloneLiteralBoilerplate(Arguments args) {
CONVERT_CHECKED(JSObject, boilerplate, args[0]);
return Heap::CopyJSObject(boilerplate);
}
@@ -131,14 +139,14 @@
}
-static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
- HandleScope scope;
- ASSERT(args.length() == 3);
- // Copy the arguments.
- Handle<FixedArray> literals = args.at<FixedArray>(0);
- int literals_index = Smi::cast(args[1])->value();
- Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
+static Handle<Object> CreateLiteralBoilerplate(
+ Handle<FixedArray> literals,
+ Handle<FixedArray> constant_properties);
+
+static Handle<Object> CreateObjectLiteralBoilerplate(
+ Handle<FixedArray> literals,
+ Handle<FixedArray> constant_properties) {
// Get the global context from the literals array. This is the
// context in which the function was created and we use the object
// function from this context to create the object literal. We do
@@ -161,6 +169,13 @@
for (int index = 0; index < length; index +=2) {
Handle<Object> key(constant_properties->get(index+0));
Handle<Object> value(constant_properties->get(index+1));
+ if (value->IsFixedArray()) {
+ // The value contains the constant_properties of a
+ // simple object literal.
+ Handle<FixedArray> array = Handle<FixedArray>::cast(value);
+ value = CreateLiteralBoilerplate(literals, array);
+ if (value.is_null()) return value;
+ }
Handle<Object> result;
uint32_t element_index = 0;
if (key->IsSymbol()) {
@@ -185,39 +200,96 @@
// 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();
+ if (result.is_null()) return result;
}
}
- // Update the functions literal and return the boilerplate.
- literals->set(literals_index, *boilerplate);
-
- return *boilerplate;
+ return boilerplate;
}
-static Object* Runtime_CreateArrayLiteral(Arguments args) {
+static Handle<Object> CreateArrayLiteralBoilerplate(
+ Handle<FixedArray> literals,
+ Handle<FixedArray> elements) {
+ // Create the JSArray.
+ Handle<JSFunction> constructor(
+ JSFunction::GlobalContextFromLiterals(*literals)->array_function());
+ Handle<Object> object = Factory::NewJSObject(constructor);
+
+ Handle<Object> copied_elements = Factory::CopyFixedArray(elements);
+
+ Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
+ for (int i = 0; i < content->length(); i++) {
+ if (content->get(i)->IsFixedArray()) {
+ // The value contains the constant_properties of a
+ // simple object literal.
+ Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
+ Handle<Object> result = CreateLiteralBoilerplate(literals, fa);
+ if (result.is_null()) return result;
+ content->set(i, *result);
+ }
+ }
+
+ // Set the elements.
+ Handle<JSArray>::cast(object)->SetContent(*content);
+ return object;
+}
+
+
+static Handle<Object> CreateLiteralBoilerplate(
+ Handle<FixedArray> literals,
+ Handle<FixedArray> array) {
+ Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
+ switch (CompileTimeValue::GetType(array)) {
+ case CompileTimeValue::OBJECT_LITERAL:
+ return CreateObjectLiteralBoilerplate(literals, elements);
+ case CompileTimeValue::ARRAY_LITERAL:
+ return CreateArrayLiteralBoilerplate(literals, elements);
+ default:
+ UNREACHABLE();
+ return Handle<Object>::null();
+ }
+}
+
+
+static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
+ HandleScope scope;
+ ASSERT(args.length() == 3);
+ // Copy the arguments.
+ CONVERT_ARG_CHECKED(FixedArray, literals, 0);
+ CONVERT_INT_CHECKED(literals_index, args[1]);
+ CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
+
+ Handle<Object> result =
+ CreateObjectLiteralBoilerplate(literals, constant_properties);
+
+ if (result.is_null()) return Failure::Exception();
+
+ // Update the functions literal and return the boilerplate.
+ literals->set(literals_index, *result);
+
+ return *result;
+}
+
+
+static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
// Takes a FixedArray of elements containing the literal elements of
// the array literal and produces JSArray with those elements.
// Additionally takes the literals array of the surrounding function
// which contains the context from which to get the Array function
// to use for creating the array literal.
- ASSERT(args.length() == 2);
- CONVERT_CHECKED(FixedArray, elements, args[0]);
- CONVERT_CHECKED(FixedArray, literals, args[1]);
- JSFunction* constructor =
- JSFunction::GlobalContextFromLiterals(literals)->array_function();
- // Create the JSArray.
- Object* object = Heap::AllocateJSObject(constructor);
- if (object->IsFailure()) return object;
+ HandleScope scope;
+ ASSERT(args.length() == 3);
+ CONVERT_ARG_CHECKED(FixedArray, literals, 0);
+ CONVERT_INT_CHECKED(literals_index, args[1]);
+ CONVERT_ARG_CHECKED(FixedArray, elements, 2);
- // Copy the elements.
- Object* content = elements->Copy();
- if (content->IsFailure()) return content;
+ Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
+ if (object.is_null()) return Failure::Exception();
- // Set the elements.
- JSArray::cast(object)->SetContent(FixedArray::cast(content));
- return object;
+ // Update the functions literal and return the boilerplate.
+ literals->set(literals_index, *object);
+ return *object;
}
@@ -858,14 +930,21 @@
static Object* Runtime_RegExpExec(Arguments args) {
HandleScope scope;
- ASSERT(args.length() == 3);
+ ASSERT(args.length() == 4);
CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
Handle<JSRegExp> regexp(raw_regexp);
CONVERT_CHECKED(String, raw_subject, args[1]);
Handle<String> subject(raw_subject);
- Handle<Object> index(args[2]);
- ASSERT(index->IsNumber());
- Handle<Object> result = RegExpImpl::Exec(regexp, subject, index);
+ // Due to the way the JS files are constructed this must be less than the
+ // length of a string, i.e. it is always a Smi. We check anyway for security.
+ CONVERT_CHECKED(Smi, index, args[2]);
+ CONVERT_CHECKED(JSArray, raw_last_match_info, args[3]);
+ Handle<JSArray> last_match_info(raw_last_match_info);
+ CHECK(last_match_info->HasFastElements());
+ Handle<Object> result = RegExpImpl::Exec(regexp,
+ subject,
+ index->value(),
+ last_match_info);
if (result.is_null()) return Failure::Exception();
return *result;
}
@@ -873,12 +952,16 @@
static Object* Runtime_RegExpExecGlobal(Arguments args) {
HandleScope scope;
- ASSERT(args.length() == 2);
+ ASSERT(args.length() == 3);
CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
Handle<JSRegExp> regexp(raw_regexp);
CONVERT_CHECKED(String, raw_subject, args[1]);
Handle<String> subject(raw_subject);
- Handle<Object> result = RegExpImpl::ExecGlobal(regexp, subject);
+ CONVERT_CHECKED(JSArray, raw_last_match_info, args[2]);
+ Handle<JSArray> last_match_info(raw_last_match_info);
+ CHECK(last_match_info->HasFastElements());
+ Handle<Object> result =
+ RegExpImpl::ExecGlobal(regexp, subject, last_match_info);
if (result.is_null()) return Failure::Exception();
return *result;
}
@@ -2310,7 +2393,7 @@
int escaped_length = 0;
int length = source->length();
{
- Access<StringInputBuffer> buffer(&string_input_buffer);
+ Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
buffer->Reset(source);
while (buffer->has_more()) {
uint16_t character = buffer->GetNext();
@@ -2338,7 +2421,7 @@
StringShape dshape(destination);
int dest_position = 0;
- Access<StringInputBuffer> buffer(&string_input_buffer);
+ Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
buffer->Rewind();
while (buffer->has_more()) {
uint16_t chr = buffer->GetNext();
@@ -2574,7 +2657,7 @@
// Convert all characters to upper case, assuming that they will fit
// in the buffer
- Access<StringInputBuffer> buffer(&string_input_buffer);
+ Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
buffer->Reset(s);
unibrow::uchar chars[Converter::kMaxWidth];
int i = 0;
@@ -4949,7 +5032,7 @@
ASSERT(args.length() >= 1);
CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
// Check that the break id is valid.
- if (Top::break_id() == 0 || break_id != Top::break_id()) {
+ if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
return Top::Throw(Heap::illegal_execution_state_symbol());
}
@@ -4967,7 +5050,7 @@
// Count all frames which are relevant to debugging stack trace.
int n = 0;
- StackFrame::Id id = Top::break_frame_id();
+ StackFrame::Id id = Debug::break_frame_id();
if (id == StackFrame::NO_ID) {
// If there is no JavaScript stack frame count is 0.
return Smi::FromInt(0);
@@ -5012,7 +5095,7 @@
CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
// Find the relevant frame with the requested index.
- StackFrame::Id id = Top::break_frame_id();
+ StackFrame::Id id = Debug::break_frame_id();
if (id == StackFrame::NO_ID) {
// If there are no JavaScript stack frames return undefined.
return Heap::undefined_value();
@@ -5700,17 +5783,13 @@
NoHandleAllocation ha;
AssertNoAllocation no_alloc;
- // Get hold of the current empty script.
- Context* context = Top::context()->global_context();
- Script* empty = context->empty_script();
-
// Scan heap for Script objects.
int count = 0;
HeapIterator iterator;
while (iterator.has_next()) {
HeapObject* obj = iterator.next();
ASSERT(obj != NULL);
- if (obj->IsScript() && obj != empty) {
+ if (obj->IsScript()) {
if (instances != NULL && count < instances_size) {
instances->set(count, obj);
}