| Index: src/runtime.cc
|
| diff --git a/src/runtime.cc b/src/runtime.cc
|
| index ab3332a2feffc712f9ab8a960aca53b720130307..6b2b0096c1d5c397be94875d046fdfe93c702d61 100644
|
| --- a/src/runtime.cc
|
| +++ b/src/runtime.cc
|
| @@ -7045,6 +7045,7 @@ static inline void StringBuilderConcatHelper(String* special,
|
| sinkchar* sink,
|
| FixedArray* fixed_array,
|
| int array_length) {
|
| + DisallowHeapAllocation no_gc;
|
| int position = 0;
|
| for (int i = 0; i < array_length; i++) {
|
| Object* element = fixed_array->get(i);
|
| @@ -7079,36 +7080,13 @@ static inline void StringBuilderConcatHelper(String* special,
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
|
| - HandleScope scope(isolate);
|
| - ASSERT(args.length() == 3);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
|
| - if (!args[1]->IsSmi()) return isolate->ThrowInvalidStringLength();
|
| - int array_length = args.smi_at(1);
|
| - CONVERT_ARG_HANDLE_CHECKED(String, special, 2);
|
| -
|
| - // This assumption is used by the slice encoding in one or two smis.
|
| - ASSERT(Smi::kMaxValue >= String::kMaxLength);
|
| -
|
| - JSObject::EnsureCanContainHeapObjectElements(array);
|
| -
|
| - int special_length = special->length();
|
| - if (!array->HasFastObjectElements()) {
|
| - return isolate->Throw(isolate->heap()->illegal_argument_string());
|
| - }
|
| - FixedArray* fixed_array = FixedArray::cast(array->elements());
|
| - if (fixed_array->length() < array_length) {
|
| - array_length = fixed_array->length();
|
| - }
|
| -
|
| - if (array_length == 0) {
|
| - return isolate->heap()->empty_string();
|
| - } else if (array_length == 1) {
|
| - Object* first = fixed_array->get(0);
|
| - if (first->IsString()) return first;
|
| - }
|
| -
|
| - bool one_byte = special->HasOnlyOneByteChars();
|
| +// Returns the result length of the concatenation.
|
| +// On illegal argument, -1 is returned.
|
| +static inline int StringBuilderConcatLength(int special_length,
|
| + FixedArray* fixed_array,
|
| + int array_length,
|
| + bool* one_byte) {
|
| + DisallowHeapAllocation no_gc;
|
| int position = 0;
|
| for (int i = 0; i < array_length; i++) {
|
| int increment = 0;
|
| @@ -7127,66 +7105,97 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
|
| len = -smi_value;
|
| // Get the position and check that it is a positive smi.
|
| i++;
|
| - if (i >= array_length) {
|
| - return isolate->Throw(isolate->heap()->illegal_argument_string());
|
| - }
|
| + if (i >= array_length) return -1;
|
| Object* next_smi = fixed_array->get(i);
|
| - if (!next_smi->IsSmi()) {
|
| - return isolate->Throw(isolate->heap()->illegal_argument_string());
|
| - }
|
| + if (!next_smi->IsSmi()) return -1;
|
| pos = Smi::cast(next_smi)->value();
|
| - if (pos < 0) {
|
| - return isolate->Throw(isolate->heap()->illegal_argument_string());
|
| - }
|
| + if (pos < 0) return -1;
|
| }
|
| ASSERT(pos >= 0);
|
| ASSERT(len >= 0);
|
| - if (pos > special_length || len > special_length - pos) {
|
| - return isolate->Throw(isolate->heap()->illegal_argument_string());
|
| - }
|
| + if (pos > special_length || len > special_length - pos) return -1;
|
| increment = len;
|
| } else if (elt->IsString()) {
|
| String* element = String::cast(elt);
|
| int element_length = element->length();
|
| increment = element_length;
|
| - if (one_byte && !element->HasOnlyOneByteChars()) {
|
| - one_byte = false;
|
| + if (*one_byte && !element->HasOnlyOneByteChars()) {
|
| + *one_byte = false;
|
| }
|
| } else {
|
| ASSERT(!elt->IsTheHole());
|
| - return isolate->Throw(isolate->heap()->illegal_argument_string());
|
| + return -1;
|
| }
|
| if (increment > String::kMaxLength - position) {
|
| - return isolate->ThrowInvalidStringLength();
|
| + return kMaxInt; // Provoke throw on allocation.
|
| }
|
| position += increment;
|
| }
|
| + return position;
|
| +}
|
|
|
| - int length = position;
|
| - Object* object;
|
|
|
| - if (one_byte) {
|
| - { MaybeObject* maybe_object =
|
| - isolate->heap()->AllocateRawOneByteString(length);
|
| - if (!maybe_object->ToObject(&object)) return maybe_object;
|
| +RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
|
| + HandleScope scope(isolate);
|
| + ASSERT(args.length() == 3);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
|
| + if (!args[1]->IsSmi()) return isolate->ThrowInvalidStringLength();
|
| + int array_length = args.smi_at(1);
|
| + CONVERT_ARG_HANDLE_CHECKED(String, special, 2);
|
| +
|
| + // This assumption is used by the slice encoding in one or two smis.
|
| + ASSERT(Smi::kMaxValue >= String::kMaxLength);
|
| +
|
| + JSObject::EnsureCanContainHeapObjectElements(array);
|
| +
|
| + int special_length = special->length();
|
| + if (!array->HasFastObjectElements()) {
|
| + return isolate->Throw(isolate->heap()->illegal_argument_string());
|
| + }
|
| +
|
| + int length;
|
| + bool one_byte = special->HasOnlyOneByteChars();
|
| +
|
| + { DisallowHeapAllocation no_gc;
|
| + FixedArray* fixed_array = FixedArray::cast(array->elements());
|
| + if (fixed_array->length() < array_length) {
|
| + array_length = fixed_array->length();
|
| + }
|
| +
|
| + if (array_length == 0) {
|
| + return isolate->heap()->empty_string();
|
| + } else if (array_length == 1) {
|
| + Object* first = fixed_array->get(0);
|
| + if (first->IsString()) return first;
|
| }
|
| - SeqOneByteString* answer = SeqOneByteString::cast(object);
|
| + length = StringBuilderConcatLength(
|
| + special_length, fixed_array, array_length, &one_byte);
|
| + }
|
| +
|
| + if (length == -1) {
|
| + return isolate->Throw(isolate->heap()->illegal_argument_string());
|
| + }
|
| +
|
| + if (one_byte) {
|
| + Handle<SeqOneByteString> answer;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, answer,
|
| + isolate->factory()->NewRawOneByteString(length));
|
| StringBuilderConcatHelper(*special,
|
| answer->GetChars(),
|
| - fixed_array,
|
| + FixedArray::cast(array->elements()),
|
| array_length);
|
| - return answer;
|
| + return *answer;
|
| } else {
|
| - { MaybeObject* maybe_object =
|
| - isolate->heap()->AllocateRawTwoByteString(length);
|
| - if (!maybe_object->ToObject(&object)) return maybe_object;
|
| - }
|
| - SeqTwoByteString* answer = SeqTwoByteString::cast(object);
|
| + Handle<SeqTwoByteString> answer;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, answer,
|
| + isolate->factory()->NewRawTwoByteString(length));
|
| StringBuilderConcatHelper(*special,
|
| answer->GetChars(),
|
| - fixed_array,
|
| + FixedArray::cast(array->elements()),
|
| array_length);
|
| - return answer;
|
| + return *answer;
|
| }
|
| }
|
|
|
| @@ -8814,10 +8823,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
|
| }
|
|
|
| for (int i = 0; i < argc; ++i) {
|
| - MaybeObject* maybe = args[1 + i];
|
| - Object* object;
|
| - if (!maybe->To<Object>(&object)) return maybe;
|
| - argv[i] = Handle<Object>(object, isolate);
|
| + argv[i] = Handle<Object>(args[1 + i], isolate);
|
| }
|
|
|
| Handle<JSReceiver> hfun(fun);
|
| @@ -9716,9 +9722,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
|
| // Compile source string in the native context.
|
| ParseRestriction restriction = function_literal_only
|
| ? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION;
|
| - Handle<JSFunction> fun = Compiler::GetFunctionFromEval(
|
| - source, context, SLOPPY, restriction, RelocInfo::kNoPosition);
|
| - RETURN_IF_EMPTY_HANDLE(isolate, fun);
|
| + Handle<JSFunction> fun;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, fun,
|
| + Compiler::GetFunctionFromEval(
|
| + source, context, SLOPPY, restriction, RelocInfo::kNoPosition));
|
| return *fun;
|
| }
|
|
|
| @@ -9745,10 +9753,12 @@ static ObjectPair CompileGlobalEval(Isolate* isolate,
|
| // Deal with a normal eval call with a string argument. Compile it
|
| // and return the compiled function bound in the local context.
|
| static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
|
| - Handle<JSFunction> compiled = Compiler::GetFunctionFromEval(
|
| - source, context, strict_mode, restriction, scope_position);
|
| - RETURN_IF_EMPTY_HANDLE_VALUE(isolate, compiled,
|
| - MakePair(Failure::Exception(), NULL));
|
| + Handle<JSFunction> compiled;
|
| + ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
| + isolate, compiled,
|
| + Compiler::GetFunctionFromEval(
|
| + source, context, strict_mode, restriction, scope_position),
|
| + MakePair(Failure::Exception(), NULL));
|
| return MakePair(*compiled, *receiver);
|
| }
|
|
|
| @@ -12771,29 +12781,32 @@ MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeArgumentsObject(
|
|
|
|
|
| // Compile and evaluate source for the given context.
|
| -static MaybeObject* DebugEvaluate(Isolate* isolate,
|
| - Handle<Context> context,
|
| - Handle<Object> context_extension,
|
| - Handle<Object> receiver,
|
| - Handle<String> source) {
|
| +static MaybeHandle<Object> DebugEvaluate(Isolate* isolate,
|
| + Handle<Context> context,
|
| + Handle<Object> context_extension,
|
| + Handle<Object> receiver,
|
| + Handle<String> source) {
|
| if (context_extension->IsJSObject()) {
|
| Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
|
| Handle<JSFunction> closure(context->closure(), isolate);
|
| context = isolate->factory()->NewWithContext(closure, context, extension);
|
| }
|
|
|
| - Handle<JSFunction> eval_fun =
|
| + Handle<JSFunction> eval_fun;
|
| + ASSIGN_RETURN_ON_EXCEPTION(
|
| + isolate, eval_fun,
|
| Compiler::GetFunctionFromEval(source,
|
| context,
|
| SLOPPY,
|
| NO_PARSE_RESTRICTION,
|
| - RelocInfo::kNoPosition);
|
| - RETURN_IF_EMPTY_HANDLE(isolate, eval_fun);
|
| + RelocInfo::kNoPosition),
|
| + Object);
|
|
|
| Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + ASSIGN_RETURN_ON_EXCEPTION(
|
| isolate, result,
|
| - Execution::Call(isolate, eval_fun, receiver, 0, NULL));
|
| + Execution::Call(isolate, eval_fun, receiver, 0, NULL),
|
| + Object);
|
|
|
| // Skip the global proxy as it has no properties and always delegates to the
|
| // real global object.
|
| @@ -12803,7 +12816,7 @@ static MaybeObject* DebugEvaluate(Isolate* isolate,
|
|
|
| // Clear the oneshot breakpoints so that the debugger does not step further.
|
| isolate->debug()->ClearStepping();
|
| - return *result;
|
| + return result;
|
| }
|
|
|
|
|
| @@ -12867,13 +12880,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
|
| context = isolate->factory()->NewWithContext(function, context, materialized);
|
|
|
| Handle<Object> receiver(frame->receiver(), isolate);
|
| - Object* evaluate_result_object;
|
| - { MaybeObject* maybe_result =
|
| - DebugEvaluate(isolate, context, context_extension, receiver, source);
|
| - if (!maybe_result->ToObject(&evaluate_result_object)) return maybe_result;
|
| - }
|
| -
|
| - Handle<Object> result(evaluate_result_object, isolate);
|
| + Handle<Object> result;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, result,
|
| + DebugEvaluate(isolate, context, context_extension, receiver, source));
|
|
|
| // Write back potential changes to materialized stack locals to the stack.
|
| UpdateStackLocalsFromMaterializedObject(
|
| @@ -12915,7 +12925,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
|
| // debugger was invoked.
|
| Handle<Context> context = isolate->native_context();
|
| Handle<Object> receiver = isolate->global_object();
|
| - return DebugEvaluate(isolate, context, context_extension, receiver, source);
|
| + Handle<Object> result;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, result,
|
| + DebugEvaluate(isolate, context, context_extension, receiver, source));
|
| + return *result;
|
| }
|
|
|
|
|
|
|