Push version 3.0.3 to trunk.
Reapplied all changes for version 3.0.1.
Improved debugger protocol for remote debugging.
Added experimental support for using gyp to generate build files for V8.
Fixed implementation of String::Write in the API (issue 975).
git-svn-id: http://v8.googlecode.com/svn/trunk@6061 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/runtime.cc b/src/runtime.cc
index efdb508..0fd2f8b 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -614,22 +614,6 @@
}
-// Sets the magic number that identifies a function as one of the special
-// math functions that can be inlined.
-static MaybeObject* Runtime_SetMathFunctionId(Arguments args) {
- NoHandleAllocation ha;
- ASSERT(args.length() == 2);
- CONVERT_CHECKED(JSFunction, function, args[0]);
- CONVERT_CHECKED(Smi, id, args[1]);
- RUNTIME_ASSERT(id->value() >= 0);
- RUNTIME_ASSERT(id->value() < SharedFunctionInfo::max_math_id_number());
-
- function->shared()->set_math_function_id(id->value());
-
- return Heap::undefined_value();
-}
-
-
static MaybeObject* Runtime_IsConstructCall(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 0);
@@ -3516,7 +3500,8 @@
CONVERT_ARG_CHECKED(JSObject, obj, 0);
CONVERT_CHECKED(String, name, args[1]);
CONVERT_CHECKED(Smi, flag_setter, args[2]);
- CONVERT_CHECKED(JSFunction, fun, args[3]);
+ Object* fun = args[3];
+ RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
CONVERT_CHECKED(Smi, flag_attr, args[4]);
int unchecked = flag_attr->value();
RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
@@ -3572,7 +3557,7 @@
}
LookupResult result;
- js_object->LocalLookupRealNamedProperty(*name, &result);
+ js_object->LookupRealNamedProperty(*name, &result);
// Take special care when attributes are different and there is already
// a property. For simplicity we normalize the property which enables us
@@ -3580,7 +3565,8 @@
// map. The current version of SetObjectProperty does not handle attributes
// correctly in the case where a property is a field and is reset with
// new attributes.
- if (result.IsProperty() && attr != result.GetAttributes()) {
+ if (result.IsProperty() &&
+ (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
// New attributes - normalize to avoid writing to instance descriptor
NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
// Use IgnoreAttributes version since a readonly property may be
@@ -4546,42 +4532,53 @@
static const unsigned int kQuoteTableLength = 128u;
-static const char* const JsonQuotes[kQuoteTableLength] = {
- "\\u0000", "\\u0001", "\\u0002", "\\u0003",
- "\\u0004", "\\u0005", "\\u0006", "\\u0007",
- "\\b", "\\t", "\\n", "\\u000b",
- "\\f", "\\r", "\\u000e", "\\u000f",
- "\\u0010", "\\u0011", "\\u0012", "\\u0013",
- "\\u0014", "\\u0015", "\\u0016", "\\u0017",
- "\\u0018", "\\u0019", "\\u001a", "\\u001b",
- "\\u001c", "\\u001d", "\\u001e", "\\u001f",
- NULL, NULL, "\\\"", NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- "\\\\", NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
-};
+static const int kJsonQuotesCharactersPerEntry = 8;
+static const char* const JsonQuotes =
+ "\\u0000 \\u0001 \\u0002 \\u0003 "
+ "\\u0004 \\u0005 \\u0006 \\u0007 "
+ "\\b \\t \\n \\u000b "
+ "\\f \\r \\u000e \\u000f "
+ "\\u0010 \\u0011 \\u0012 \\u0013 "
+ "\\u0014 \\u0015 \\u0016 \\u0017 "
+ "\\u0018 \\u0019 \\u001a \\u001b "
+ "\\u001c \\u001d \\u001e \\u001f "
+ " ! \\\" # "
+ "$ % & ' "
+ "( ) * + "
+ ", - . / "
+ "0 1 2 3 "
+ "4 5 6 7 "
+ "8 9 : ; "
+ "< = > ? "
+ "@ A B C "
+ "D E F G "
+ "H I J K "
+ "L M N O "
+ "P Q R S "
+ "T U V W "
+ "X Y Z [ "
+ "\\\\ ] ^ _ "
+ "` a b c "
+ "d e f g "
+ "h i j k "
+ "l m n o "
+ "p q r s "
+ "t u v w "
+ "x y z { "
+ "| } ~ \177 ";
+// For a string that is less than 32k characters it should always be
+// possible to allocate it in new space.
+static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
+
+
+// Doing JSON quoting cannot make the string more than this many times larger.
+static const int kJsonQuoteWorstCaseBlowup = 6;
+
+
+// Covers the entire ASCII range (all other characters are unchanged by JSON
+// quoting).
static const byte JsonQuoteLengths[kQuoteTableLength] = {
6, 6, 6, 6, 6, 6, 6, 6,
2, 2, 2, 6, 2, 2, 6, 6,
@@ -4602,18 +4599,6 @@
};
-template <typename Char>
-Char* WriteString(Char* dst, const char* src_string) {
- char c;
- for (c = *src_string; c; c = *src_string) {
- *dst = c;
- dst++;
- src_string++;
- }
- return dst;
-}
-
-
template <typename StringType>
MaybeObject* AllocateRawString(int length);
@@ -4631,58 +4616,111 @@
template <typename Char, typename StringType>
-static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
+static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
int length = characters.length();
- int quoted_length = 0;
- for (int i = 0; i < length; i++) {
- unsigned int c = characters[i];
- if (sizeof(Char) > 1u) {
- quoted_length += (c >= kQuoteTableLength) ? 1 : JsonQuoteLengths[c];
+ const Char* read_cursor = characters.start();
+ const Char* end = read_cursor + length;
+ const int kSpaceForQuotes = 2;
+ int quoted_length = kSpaceForQuotes;
+ while (read_cursor < end) {
+ Char c = *(read_cursor++);
+ if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
+ quoted_length++;
} else {
- quoted_length += JsonQuoteLengths[c];
+ quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
}
}
- Counters::quote_json_char_count.Increment(length);
-
- // Add space for quotes.
- quoted_length += 2;
-
MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
Object* new_object;
if (!new_alloc->ToObject(&new_object)) {
- Counters::quote_json_char_recount.Increment(length);
return new_alloc;
}
StringType* new_string = StringType::cast(new_object);
+ Char* write_cursor = reinterpret_cast<Char*>(
+ new_string->address() + SeqAsciiString::kHeaderSize);
+ *(write_cursor++) = '"';
+
+ read_cursor = characters.start();
+ while (read_cursor < end) {
+ Char c = *(read_cursor++);
+ if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
+ *(write_cursor++) = c;
+ } else {
+ int len = JsonQuoteLengths[static_cast<unsigned>(c)];
+ const char* replacement = JsonQuotes +
+ static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
+ for (int i = 0; i < len; i++) {
+ *write_cursor++ = *replacement++;
+ }
+ }
+ }
+ *(write_cursor++) = '"';
+ return new_string;
+}
+
+
+template <typename Char, typename StringType>
+static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
+ int length = characters.length();
+ Counters::quote_json_char_count.Increment(length);
+ const int kSpaceForQuotes = 2;
+ int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
+ if (worst_case_length > kMaxGuaranteedNewSpaceString) {
+ return SlowQuoteJsonString<Char, StringType>(characters);
+ }
+
+ MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
+ Object* new_object;
+ if (!new_alloc->ToObject(&new_object)) {
+ return new_alloc;
+ }
+ if (!Heap::new_space()->Contains(new_object)) {
+ // Even if our string is small enough to fit in new space we still have to
+ // handle it being allocated in old space as may happen in the third
+ // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
+ // CEntryStub::GenerateCore.
+ return SlowQuoteJsonString<Char, StringType>(characters);
+ }
+ StringType* new_string = StringType::cast(new_object);
+ ASSERT(Heap::new_space()->Contains(new_string));
STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
Char* write_cursor = reinterpret_cast<Char*>(
new_string->address() + SeqAsciiString::kHeaderSize);
*(write_cursor++) = '"';
+
const Char* read_cursor = characters.start();
- if (quoted_length == length + 2) {
- CopyChars(write_cursor, read_cursor, length);
- write_cursor += length;
- } else {
- const Char* end = read_cursor + length;
- while (read_cursor < end) {
- Char c = *(read_cursor++);
- if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
- *(write_cursor++) = c;
- } else {
- const char* replacement = JsonQuotes[static_cast<unsigned>(c)];
- if (!replacement) {
- *(write_cursor++) = c;
- } else {
- write_cursor = WriteString(write_cursor, replacement);
+ const Char* end = read_cursor + length;
+ while (read_cursor < end) {
+ Char c = *(read_cursor++);
+ if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
+ *(write_cursor++) = c;
+ } else {
+ int len = JsonQuoteLengths[static_cast<unsigned>(c)];
+ const char* replacement = JsonQuotes +
+ static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
+ write_cursor[0] = replacement[0];
+ if (len > 1) {
+ write_cursor[1] = replacement[1];
+ if (len > 2) {
+ ASSERT(len == 6);
+ write_cursor[2] = replacement[2];
+ write_cursor[3] = replacement[3];
+ write_cursor[4] = replacement[4];
+ write_cursor[5] = replacement[5];
}
}
+ write_cursor += len;
}
}
*(write_cursor++) = '"';
- ASSERT_EQ(SeqAsciiString::kHeaderSize + quoted_length * sizeof(Char),
- reinterpret_cast<Address>(write_cursor) - new_string->address());
+
+ int final_length = static_cast<int>(
+ write_cursor - reinterpret_cast<Char*>(
+ new_string->address() + SeqAsciiString::kHeaderSize));
+ Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
+ final_length);
return new_string;
}
@@ -5977,37 +6015,6 @@
}
-// Helper function to compute x^y, where y is known to be an
-// integer. Uses binary decomposition to limit the number of
-// multiplications; see the discussion in "Hacker's Delight" by Henry
-// S. Warren, Jr., figure 11-6, page 213.
-static double powi(double x, int y) {
- ASSERT(y != kMinInt);
- unsigned n = (y < 0) ? -y : y;
- double m = x;
- double p = 1;
- while (true) {
- if ((n & 1) != 0) p *= m;
- n >>= 1;
- if (n == 0) {
- if (y < 0) {
- // Unfortunately, we have to be careful when p has reached
- // infinity in the computation, because sometimes the higher
- // internal precision in the pow() implementation would have
- // given us a finite p. This happens very rarely.
- double result = 1.0 / p;
- return (result == 0 && isinf(p))
- ? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
- : result;
- } else {
- return p;
- }
- }
- m *= m;
- }
-}
-
-
static MaybeObject* Runtime_Math_pow(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -6019,31 +6026,11 @@
// custom powi() function than the generic pow().
if (args[1]->IsSmi()) {
int y = Smi::cast(args[1])->value();
- return Heap::NumberFromDouble(powi(x, y));
+ return Heap::NumberFromDouble(power_double_int(x, y));
}
CONVERT_DOUBLE_CHECKED(y, args[1]);
-
- if (!isinf(x)) {
- if (y == 0.5) {
- // It's not uncommon to use Math.pow(x, 0.5) to compute the
- // square root of a number. To speed up such computations, we
- // explictly check for this case and use the sqrt() function
- // which is faster than pow().
- return Heap::AllocateHeapNumber(sqrt(x));
- } else if (y == -0.5) {
- // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5).
- return Heap::AllocateHeapNumber(1.0 / sqrt(x));
- }
- }
-
- if (y == 0) {
- return Smi::FromInt(1);
- } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
- return Heap::nan_value();
- } else {
- return Heap::AllocateHeapNumber(pow(x, y));
- }
+ return Heap::AllocateHeapNumber(power_double_double(x, y));
}
// Fast version of Math.pow if we know that y is not an integer and
@@ -6054,11 +6041,11 @@
CONVERT_DOUBLE_CHECKED(x, args[0]);
CONVERT_DOUBLE_CHECKED(y, args[1]);
if (y == 0) {
- return Smi::FromInt(1);
+ return Smi::FromInt(1);
} else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
- return Heap::nan_value();
+ return Heap::nan_value();
} else {
- return Heap::AllocateHeapNumber(pow(x, y));
+ return Heap::AllocateHeapNumber(pow(x, y));
}
}
@@ -6891,12 +6878,17 @@
if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
DeoptimizationInputData* data = DeoptimizationInputData::cast(
function->code()->deoptimization_data());
- if (FLAG_trace_osr) {
- PrintF("[on-stack replacement offset %d in optimized code]\n",
+ if (data->OsrPcOffset()->value() >= 0) {
+ if (FLAG_trace_osr) {
+ PrintF("[on-stack replacement offset %d in optimized code]\n",
data->OsrPcOffset()->value());
+ }
+ ASSERT(data->OsrAstId()->value() == ast_id);
+ } else {
+ // We may never generate the desired OSR entry if we emit an
+ // early deoptimize.
+ succeeded = false;
}
- ASSERT(data->OsrAstId()->value() == ast_id);
- ASSERT(data->OsrPcOffset()->value() >= 0);
} else {
succeeded = false;
}
@@ -7671,13 +7663,13 @@
}
-// Push an array unto an array of arrays if it is not already in the
+// Push an object unto an array of objects if it is not already in the
// array. Returns true if the element was pushed on the stack and
// false otherwise.
static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ASSERT(args.length() == 2);
CONVERT_CHECKED(JSArray, array, args[0]);
- CONVERT_CHECKED(JSArray, element, args[1]);
+ CONVERT_CHECKED(JSObject, element, args[1]);
RUNTIME_ASSERT(array->HasFastElements());
int length = Smi::cast(array->length())->value();
FixedArray* elements = FixedArray::cast(array->elements());
@@ -9688,7 +9680,7 @@
// Check the execution state and decode arguments frame and source to be
// evaluated.
- ASSERT(args.length() == 4);
+ ASSERT(args.length() == 5);
Object* check_result;
{ MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
if (!maybe_check_result->ToObject(&check_result)) {
@@ -9698,6 +9690,7 @@
CONVERT_CHECKED(Smi, wrapped_id, args[1]);
CONVERT_ARG_CHECKED(String, source, 2);
CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
+ Handle<Object> additional_context(args[4]);
// Handle the processing of break.
DisableBreak disable_break_save(disable_break);
@@ -9748,6 +9741,11 @@
Handle<Context> function_context(frame_context->fcontext());
context = CopyWithContextChain(frame_context, context);
+ if (additional_context->IsJSObject()) {
+ context = Factory::NewWithContext(context,
+ Handle<JSObject>::cast(additional_context), false);
+ }
+
// 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
@@ -9802,7 +9800,7 @@
// Check the execution state and decode arguments frame and source to be
// evaluated.
- ASSERT(args.length() == 3);
+ ASSERT(args.length() == 4);
Object* check_result;
{ MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
if (!maybe_check_result->ToObject(&check_result)) {
@@ -9811,6 +9809,7 @@
}
CONVERT_ARG_CHECKED(String, source, 1);
CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
+ Handle<Object> additional_context(args[3]);
// Handle the processing of break.
DisableBreak disable_break_save(disable_break);
@@ -9829,11 +9828,24 @@
// debugger was invoked.
Handle<Context> context = Top::global_context();
+ bool is_global = true;
+
+ if (additional_context->IsJSObject()) {
+ // Create a function context first, than put 'with' context on top of it.
+ Handle<JSFunction> go_between = Factory::NewFunction(
+ Factory::empty_string(), Factory::undefined_value());
+ go_between->set_context(*context);
+ context =
+ Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
+ context->set_extension(JSObject::cast(*additional_context));
+ is_global = false;
+ }
+
// Compile the source to be evaluated.
Handle<SharedFunctionInfo> shared =
Compiler::CompileEval(source,
context,
- true);
+ is_global);
if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> compiled_function =
Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,