| Index: src/runtime.cc
|
| ===================================================================
|
| --- src/runtime.cc (revision 6904)
|
| +++ src/runtime.cc (working copy)
|
| @@ -644,23 +644,6 @@
|
| }
|
|
|
|
|
| -// Sets the magic number that identifies a function as one of the special
|
| -// math functions that can be inlined.
|
| -static MaybeObject* Runtime_SetMathFunctionId(RUNTIME_CALLING_CONVENTION) {
|
| - RUNTIME_GET_ISOLATE;
|
| - 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 isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| static MaybeObject* Runtime_IsConstructCall(RUNTIME_CALLING_CONVENTION) {
|
| RUNTIME_GET_ISOLATE;
|
| NoHandleAllocation ha;
|
| @@ -3675,7 +3658,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);
|
| @@ -3733,7 +3717,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
|
| @@ -3741,7 +3725,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
|
| @@ -4752,42 +4737,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,
|
| @@ -4808,18 +4804,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);
|
|
|
| @@ -4837,61 +4821,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)];
|
| }
|
| }
|
| + MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
|
| + Object* new_object;
|
| + if (!new_alloc->ToObject(&new_object)) {
|
| + 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);
|
| + }
|
|
|
| - // Add space for quotes.
|
| - quoted_length += 2;
|
| -
|
| - MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
|
| + MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
|
| Object* new_object;
|
| if (!new_alloc->ToObject(&new_object)) {
|
| - COUNTERS->quote_json_char_recount()->Increment(length);
|
| 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(
|
| - static_cast<int64_t>(
|
| - SeqAsciiString::kHeaderSize + quoted_length * sizeof(Char)),
|
| - static_cast<int64_t>(
|
| - 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;
|
| }
|
|
|
| @@ -6256,37 +6290,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(RUNTIME_CALLING_CONVENTION) {
|
| RUNTIME_GET_ISOLATE;
|
| NoHandleAllocation ha;
|
| @@ -6299,31 +6302,11 @@
|
| // custom powi() function than the generic pow().
|
| if (args[1]->IsSmi()) {
|
| int y = Smi::cast(args[1])->value();
|
| - return isolate->heap()->NumberFromDouble(powi(x, y));
|
| + return isolate->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 isolate->heap()->AllocateHeapNumber(sqrt(x));
|
| - } else if (y == -0.5) {
|
| - // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5).
|
| - return isolate->heap()->AllocateHeapNumber(1.0 / sqrt(x));
|
| - }
|
| - }
|
| -
|
| - if (y == 0) {
|
| - return Smi::FromInt(1);
|
| - } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
|
| - return isolate->heap()->nan_value();
|
| - } else {
|
| - return isolate->heap()->AllocateHeapNumber(pow(x, y));
|
| - }
|
| + return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
|
| }
|
|
|
| // Fast version of Math.pow if we know that y is not an integer and
|
| @@ -6335,11 +6318,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 isolate->heap()->nan_value();
|
| + return isolate->heap()->nan_value();
|
| } else {
|
| - return isolate->heap()->AllocateHeapNumber(pow(x, y));
|
| + return isolate->heap()->AllocateHeapNumber(pow(x, y));
|
| }
|
| }
|
|
|
| @@ -7194,12 +7177,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;
|
| }
|
| @@ -7533,7 +7521,7 @@
|
| // extension object itself.
|
| if ((attributes & READ_ONLY) == 0 ||
|
| (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
|
| - Handle<Object> set = SetProperty(context_ext, name, value, attributes);
|
| + Handle<Object> set = SetProperty(context_ext, name, value, NONE);
|
| if (set.is_null()) {
|
| // Failure::Exception is converted to a null handle in the
|
| // handle-based methods such as SetProperty. We therefore need
|
| @@ -8021,14 +8009,14 @@
|
| }
|
|
|
|
|
| -// 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(RUNTIME_CALLING_CONVENTION) {
|
| RUNTIME_GET_ISOLATE;
|
| 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());
|
| @@ -10124,7 +10112,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,
|
| isolate);
|
| @@ -10135,6 +10123,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);
|
| @@ -10187,6 +10176,11 @@
|
| Handle<Context> function_context(frame_context->fcontext());
|
| context = CopyWithContextChain(frame_context, context);
|
|
|
| + if (additional_context->IsJSObject()) {
|
| + context = isolate->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
|
| @@ -10241,7 +10235,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,
|
| isolate);
|
| @@ -10251,6 +10245,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);
|
| @@ -10269,11 +10264,26 @@
|
| // debugger was invoked.
|
| Handle<Context> context = isolate->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 = isolate->factory()->NewFunction(
|
| + isolate->factory()->empty_string(),
|
| + isolate->factory()->undefined_value());
|
| + go_between->set_context(*context);
|
| + context =
|
| + isolate->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>(
|
|
|