Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(164)

Unified Diff: src/runtime.cc

Issue 7348008: Merge up to 8597 to experimental/gc from the bleeding edge. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: '' Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/runtime.h ('k') | src/runtime-profiler.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/runtime.cc
===================================================================
--- src/runtime.cc (revision 8618)
+++ src/runtime.cc (working copy)
@@ -45,6 +45,7 @@
#include "json-parser.h"
#include "liveedit.h"
#include "liveobjectlist-inl.h"
+#include "misc-intrinsics.h"
#include "parser.h"
#include "platform.h"
#include "runtime-profiler.h"
@@ -81,19 +82,19 @@
RUNTIME_ASSERT(obj->IsBoolean()); \
bool name = (obj)->IsTrue();
-// Cast the given object to a Smi and store its value in an int variable
-// with the given name. If the object is not a Smi call IllegalOperation
+// Cast the given argument to a Smi and store its value in an int variable
+// with the given name. If the argument is not a Smi call IllegalOperation
// and return.
-#define CONVERT_SMI_CHECKED(name, obj) \
- RUNTIME_ASSERT(obj->IsSmi()); \
- int name = Smi::cast(obj)->value();
+#define CONVERT_SMI_ARG_CHECKED(name, index) \
+ RUNTIME_ASSERT(args[index]->IsSmi()); \
+ int name = args.smi_at(index);
-// 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
+// Cast the given argument to a double and store it in a variable with
+// the given name. If the argument is not a number (as opposed to
// the number not-a-number) call IllegalOperation and return.
-#define CONVERT_DOUBLE_CHECKED(name, obj) \
- RUNTIME_ASSERT(obj->IsNumber()); \
- double name = (obj)->Number();
+#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
+ RUNTIME_ASSERT(args[index]->IsNumber()); \
+ double name = args.number_at(index);
// Call the specified converter on the object *comand store the result in
// a variable of the specified type with the given name. If the
@@ -482,7 +483,7 @@
HandleScope scope(isolate);
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
- CONVERT_SMI_CHECKED(literals_index, args[1]);
+ CONVERT_SMI_ARG_CHECKED(literals_index, 1);
CONVERT_ARG_CHECKED(FixedArray, elements, 2);
Handle<Object> object =
@@ -499,9 +500,9 @@
HandleScope scope(isolate);
ASSERT(args.length() == 4);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
- CONVERT_SMI_CHECKED(literals_index, args[1]);
+ CONVERT_SMI_ARG_CHECKED(literals_index, 1);
CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
- CONVERT_SMI_CHECKED(flags, args[3]);
+ CONVERT_SMI_ARG_CHECKED(flags, 3);
bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
@@ -525,9 +526,9 @@
HandleScope scope(isolate);
ASSERT(args.length() == 4);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
- CONVERT_SMI_CHECKED(literals_index, args[1]);
+ CONVERT_SMI_ARG_CHECKED(literals_index, 1);
CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
- CONVERT_SMI_CHECKED(flags, args[3]);
+ CONVERT_SMI_ARG_CHECKED(flags, 3);
bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
@@ -551,7 +552,7 @@
HandleScope scope(isolate);
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
- CONVERT_SMI_CHECKED(literals_index, args[1]);
+ CONVERT_SMI_ARG_CHECKED(literals_index, 1);
CONVERT_ARG_CHECKED(FixedArray, elements, 2);
// Check if boilerplate exists. If not, create it first.
@@ -570,7 +571,7 @@
HandleScope scope(isolate);
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
- CONVERT_SMI_CHECKED(literals_index, args[1]);
+ CONVERT_SMI_ARG_CHECKED(literals_index, 1);
CONVERT_ARG_CHECKED(FixedArray, elements, 2);
// Check if boilerplate exists. If not, create it first.
@@ -594,37 +595,26 @@
Object* handler = args[0];
Object* prototype = args[1];
Object* used_prototype =
- (prototype->IsJSObject() || prototype->IsJSProxy()) ? prototype
- : isolate->heap()->null_value();
+ prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
return isolate->heap()->AllocateJSProxy(handler, used_prototype);
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
- ASSERT(args.length() == 2);
- CONVERT_CHECKED(String, key, args[0]);
- Object* value = args[1];
- RUNTIME_ASSERT(!value->IsFailure());
- // Create a catch context extension object.
- JSFunction* constructor =
- isolate->context()->global_context()->
- context_extension_function();
- Object* object;
- { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
- if (!maybe_object->ToObject(&object)) return maybe_object;
- }
- // Assign the exception value to the catch variable and make sure
- // that the catch variable is DontDelete.
- { MaybeObject* maybe_value =
- // 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;
+RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
+ ASSERT(args.length() == 1);
+ Object* obj = args[0];
+ return obj->IsJSProxy()
+ ? isolate->heap()->true_value() : isolate->heap()->false_value();
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
+ ASSERT(args.length() == 1);
+ CONVERT_CHECKED(JSProxy, proxy, args[0]);
+ return proxy->handler();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -634,6 +624,18 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 1);
+ Object* obj = args[0];
+ do {
+ obj = obj->GetPrototype();
+ } while (obj->IsJSObject() &&
+ JSObject::cast(obj)->map()->is_hidden_prototype());
+ return obj;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -874,7 +876,13 @@
ASSERT(proto->IsJSGlobalObject());
holder = Handle<JSObject>(JSObject::cast(proto));
}
- NumberDictionary* dictionary = holder->element_dictionary();
+ FixedArray* elements = FixedArray::cast(holder->elements());
+ NumberDictionary* dictionary = NULL;
+ if (elements->map() == heap->non_strict_arguments_elements_map()) {
+ dictionary = NumberDictionary::cast(elements->get(1));
+ } else {
+ dictionary = NumberDictionary::cast(elements);
+ }
int entry = dictionary->FindEntry(index);
ASSERT(entry != NumberDictionary::kNotFound);
PropertyDetails details = dictionary->DetailsAt(entry);
@@ -1084,9 +1092,8 @@
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());
+ bool is_eval = args.smi_at(2) == 1;
+ StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
// Compute the property attributes. According to ECMA-262, section
@@ -1225,13 +1232,12 @@
CONVERT_ARG_CHECKED(Context, context, 0);
Handle<String> name(String::cast(args[1]));
- PropertyAttributes mode =
- static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
+ PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
Handle<Object> initial_value(args[3], isolate);
- // Declarations are always done in the function context.
- context = Handle<Context>(context->fcontext());
+ // Declarations are always done in a function or global context.
+ context = Handle<Context>(context->declaration_context());
int index;
PropertyAttributes attributes;
@@ -1285,7 +1291,7 @@
Handle<JSObject> context_ext;
if (context->has_extension()) {
// The function context's extension context exists - use it.
- context_ext = Handle<JSObject>(context->extension());
+ context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
} else {
// The function context's extension context does not exists - allocate
// it.
@@ -1339,8 +1345,7 @@
CONVERT_ARG_CHECKED(String, name, 0);
GlobalObject* global = isolate->context()->global();
RUNTIME_ASSERT(args[1]->IsSmi());
- StrictModeFlag strict_mode =
- static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
+ StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
// According to ECMA-262, section 12.2, page 62, the property must
@@ -1519,8 +1524,8 @@
CONVERT_ARG_CHECKED(Context, context, 1);
Handle<String> name(String::cast(args[2]));
- // Initializations are always done in the function context.
- context = Handle<Context>(context->fcontext());
+ // Initializations are always done in a function or global context.
+ context = Handle<Context>(context->declaration_context());
int index;
PropertyAttributes attributes;
@@ -1541,14 +1546,12 @@
// In that case, the initialization behaves like a normal assignment
// to property 'x'.
if (index >= 0) {
- // Property was found in a context.
if (holder->IsContext()) {
- // The holder cannot be the function context. If it is, there
- // should have been a const redeclaration error when declaring
- // the const property.
- ASSERT(!holder.is_identical_to(context));
- if ((attributes & READ_ONLY) == 0) {
- Handle<Context>::cast(holder)->set(index, *value);
+ // Property was found in a context. Perform the assignment if we
+ // found some non-constant or an uninitialized constant.
+ Handle<Context> context = Handle<Context>::cast(holder);
+ if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
+ context->set(index, *value);
}
} else {
// The holder is an arguments object.
@@ -1622,7 +1625,7 @@
HandleScope scope(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSObject, object, 0);
- CONVERT_SMI_CHECKED(properties, args[1]);
+ CONVERT_SMI_ARG_CHECKED(properties, 1);
if (object->HasFastProperties()) {
NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
}
@@ -1637,7 +1640,7 @@
CONVERT_ARG_CHECKED(String, subject, 1);
// Due to the way the JS calls 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_SMI_CHECKED(index, args[2]);
+ CONVERT_SMI_ARG_CHECKED(index, 2);
CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
RUNTIME_ASSERT(last_match_info->HasFastElements());
RUNTIME_ASSERT(index >= 0);
@@ -1654,7 +1657,7 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
ASSERT(args.length() == 3);
- CONVERT_SMI_CHECKED(elements_count, args[0]);
+ CONVERT_SMI_ARG_CHECKED(elements_count, 0);
if (elements_count > JSArray::kMaxFastElementsLength) {
return isolate->ThrowIllegalOperation();
}
@@ -1809,7 +1812,7 @@
HandleScope scope(isolate);
ASSERT(args.length() == 4);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
- int index = Smi::cast(args[1])->value();
+ int index = args.smi_at(1);
Handle<String> pattern = args.at<String>(2);
Handle<String> flags = args.at<String>(3);
@@ -1855,6 +1858,15 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 1);
+
+ CONVERT_CHECKED(JSFunction, fun, args[0]);
+ fun->shared()->set_bound(true);
+ return isolate->heap()->undefined_value();
+}
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -2035,7 +2047,7 @@
HandleScope scope(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
- CONVERT_SMI_CHECKED(num, args[1]);
+ CONVERT_SMI_ARG_CHECKED(num, 1);
RUNTIME_ASSERT(num >= 0);
SetExpectedNofProperties(function, num);
return isolate->heap()->undefined_value();
@@ -2259,24 +2271,24 @@
Handle<String> joined_string;
if (is_ascii_) {
- joined_string = NewRawAsciiString(character_count_);
+ Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
AssertNoAllocation no_alloc;
- SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
char* char_buffer = seq->GetChars();
StringBuilderConcatHelper(*subject_,
char_buffer,
*array_builder_.array(),
array_builder_.length());
+ joined_string = Handle<String>::cast(seq);
} else {
// Non-ASCII.
- joined_string = NewRawTwoByteString(character_count_);
+ Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
AssertNoAllocation no_alloc;
- SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
uc16* char_buffer = seq->GetChars();
StringBuilderConcatHelper(*subject_,
char_buffer,
*array_builder_.array(),
array_builder_.length());
+ joined_string = Handle<String>::cast(seq);
}
return joined_string;
}
@@ -2294,15 +2306,13 @@
}
private:
- Handle<String> NewRawAsciiString(int size) {
- CALL_HEAP_FUNCTION(heap_->isolate(),
- heap_->AllocateRawAsciiString(size), String);
+ Handle<SeqAsciiString> NewRawAsciiString(int length) {
+ return heap_->isolate()->factory()->NewRawAsciiString(length);
}
- Handle<String> NewRawTwoByteString(int size) {
- CALL_HEAP_FUNCTION(heap_->isolate(),
- heap_->AllocateRawTwoByteString(size), String);
+ Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
+ return heap_->isolate()->factory()->NewRawTwoByteString(length);
}
@@ -2338,6 +2348,7 @@
int parts() {
return parts_.length();
}
+
private:
enum PartType {
SUBJECT_PREFIX = 1,
@@ -2614,7 +2625,7 @@
int capture_count = regexp_handle->CaptureCount();
// CompiledReplacement uses zone allocation.
- CompilationZoneScope zone(isolate, DELETE_ON_EXIT);
+ ZoneScope zone(isolate, DELETE_ON_EXIT);
CompiledReplacement compiled_replacement;
compiled_replacement.Compile(replacement_handle,
capture_count,
@@ -3091,17 +3102,17 @@
ASSERT(args.length() == 3);
CONVERT_CHECKED(String, value, args[0]);
- Object* from = args[1];
- Object* to = args[2];
int start, end;
// We have a fast integer-only case here to avoid a conversion to double in
// the common case where from and to are Smis.
- if (from->IsSmi() && to->IsSmi()) {
- start = Smi::cast(from)->value();
- end = Smi::cast(to)->value();
+ if (args[1]->IsSmi() && args[2]->IsSmi()) {
+ CONVERT_SMI_ARG_CHECKED(from_number, 1);
+ CONVERT_SMI_ARG_CHECKED(to_number, 2);
+ start = from_number;
+ end = to_number;
} else {
- CONVERT_DOUBLE_CHECKED(from_number, from);
- CONVERT_DOUBLE_CHECKED(to_number, to);
+ CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
+ CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
start = FastD2I(from_number);
end = FastD2I(to_number);
}
@@ -3131,11 +3142,11 @@
}
int length = subject->length();
- CompilationZoneScope zone_space(isolate, DELETE_ON_EXIT);
+ ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ZoneList<int> offsets(8);
+ int start;
+ int end;
do {
- int start;
- int end;
{
AssertNoAllocation no_alloc;
FixedArray* elements = FixedArray::cast(regexp_info->elements());
@@ -3144,20 +3155,23 @@
}
offsets.Add(start);
offsets.Add(end);
- int index = start < end ? end : end + 1;
- if (index > length) break;
- match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
+ if (start == end) if (++end > length) break;
+ match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
if (match.is_null()) {
return Failure::Exception();
}
} while (!match->IsNull());
int matches = offsets.length() / 2;
Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
- for (int i = 0; i < matches ; i++) {
+ Handle<String> substring = isolate->factory()->
+ NewSubString(subject, offsets.at(0), offsets.at(1));
+ elements->set(0, *substring);
+ for (int i = 1; i < matches ; i++) {
int from = offsets.at(i * 2);
int to = offsets.at(i * 2 + 1);
- Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
- elements->set(i, *match);
+ Handle<String> substring = isolate->factory()->
+ NewProperSubString(subject, from, to);
+ elements->set(i, *substring);
}
Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
result->set_length(Smi::FromInt(matches));
@@ -3307,6 +3321,7 @@
OffsetsVector registers(required_registers);
Vector<int32_t> register_vector(registers.vector(), registers.length());
int subject_length = subject->length();
+ bool first = true;
for (;;) { // Break on failure, return on exception.
RegExpImpl::IrregexpResult result =
@@ -3324,9 +3339,15 @@
}
match_end = register_vector[1];
HandleScope loop_scope(isolate);
- builder->Add(*isolate->factory()->NewSubString(subject,
- match_start,
- match_end));
+ if (!first) {
+ builder->Add(*isolate->factory()->NewProperSubString(subject,
+ match_start,
+ match_end));
+ } else {
+ builder->Add(*isolate->factory()->NewSubString(subject,
+ match_start,
+ match_end));
+ }
if (match_start != match_end) {
pos = match_end;
} else {
@@ -3339,6 +3360,7 @@
ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
return result;
}
+ first = false;
}
if (match_start >= 0) {
@@ -3390,7 +3412,7 @@
// at the end, so we have two vectors that we swap between.
OffsetsVector registers2(required_registers);
Vector<int> prev_register_vector(registers2.vector(), registers2.length());
-
+ bool first = true;
do {
int match_start = register_vector[0];
builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
@@ -3408,18 +3430,30 @@
// subject, i.e., 3 + capture count in total.
Handle<FixedArray> elements =
isolate->factory()->NewFixedArray(3 + capture_count);
- Handle<String> match = isolate->factory()->NewSubString(subject,
- match_start,
- match_end);
+ Handle<String> match;
+ if (!first) {
+ match = isolate->factory()->NewProperSubString(subject,
+ match_start,
+ match_end);
+ } else {
+ match = isolate->factory()->NewSubString(subject,
+ match_start,
+ match_end);
+ }
elements->set(0, *match);
for (int i = 1; i <= capture_count; i++) {
int start = register_vector[i * 2];
if (start >= 0) {
int end = register_vector[i * 2 + 1];
ASSERT(start <= end);
- Handle<String> substring = isolate->factory()->NewSubString(subject,
- start,
- end);
+ Handle<String> substring;
+ if (!first) {
+ substring = isolate->factory()->NewProperSubString(subject,
+ start,
+ end);
+ } else {
+ substring = isolate->factory()->NewSubString(subject, start, end);
+ }
elements->set(i, *substring);
} else {
ASSERT(register_vector[i * 2 + 1] < 0);
@@ -3449,6 +3483,7 @@
subject,
pos,
register_vector);
+ first = false;
} while (result == RegExpImpl::RE_SUCCESS);
if (result != RegExpImpl::RE_EXCEPTION) {
@@ -3495,7 +3530,8 @@
if (result_array->HasFastElements()) {
result_elements =
Handle<FixedArray>(FixedArray::cast(result_array->elements()));
- } else {
+ }
+ if (result_elements.is_null() || result_elements->length() < 16) {
result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
}
FixedArrayBuilder builder(result_elements);
@@ -3537,13 +3573,13 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
+ CONVERT_SMI_ARG_CHECKED(radix, 1);
+ RUNTIME_ASSERT(2 <= radix && radix <= 36);
// Fast case where the result is a one character string.
- if (args[0]->IsSmi() && args[1]->IsSmi()) {
- int value = Smi::cast(args[0])->value();
- int radix = Smi::cast(args[1])->value();
+ if (args[0]->IsSmi()) {
+ int value = args.smi_at(0);
if (value >= 0 && value < radix) {
- RUNTIME_ASSERT(radix <= 36);
// Character array used for conversion.
static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
return isolate->heap()->
@@ -3552,7 +3588,7 @@
}
// Slow case.
- CONVERT_DOUBLE_CHECKED(value, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(value, 0);
if (isnan(value)) {
return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
}
@@ -3562,9 +3598,6 @@
}
return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
}
- CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
- int radix = FastD2I(radix_number);
- RUNTIME_ASSERT(2 <= radix && radix <= 36);
char* str = DoubleToRadixCString(value, radix);
MaybeObject* result =
isolate->heap()->AllocateStringFromAscii(CStrVector(str));
@@ -3577,7 +3610,7 @@
NoHandleAllocation ha;
ASSERT(args.length() == 2);
- CONVERT_DOUBLE_CHECKED(value, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(value, 0);
if (isnan(value)) {
return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
}
@@ -3587,7 +3620,7 @@
}
return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
}
- CONVERT_DOUBLE_CHECKED(f_number, args[1]);
+ CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2I(f_number);
RUNTIME_ASSERT(f >= 0);
char* str = DoubleToFixedCString(value, f);
@@ -3602,7 +3635,7 @@
NoHandleAllocation ha;
ASSERT(args.length() == 2);
- CONVERT_DOUBLE_CHECKED(value, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(value, 0);
if (isnan(value)) {
return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
}
@@ -3612,7 +3645,7 @@
}
return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
}
- CONVERT_DOUBLE_CHECKED(f_number, args[1]);
+ CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2I(f_number);
RUNTIME_ASSERT(f >= -1 && f <= 20);
char* str = DoubleToExponentialCString(value, f);
@@ -3627,7 +3660,7 @@
NoHandleAllocation ha;
ASSERT(args.length() == 2);
- CONVERT_DOUBLE_CHECKED(value, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(value, 0);
if (isnan(value)) {
return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
}
@@ -3637,7 +3670,7 @@
}
return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
}
- CONVERT_DOUBLE_CHECKED(f_number, args[1]);
+ CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2I(f_number);
RUNTIME_ASSERT(f >= 1 && f <= 21);
char* str = DoubleToPrecisionCString(value, f);
@@ -3727,8 +3760,7 @@
if (name->AsArrayIndex(&index)) {
return GetElementOrCharAt(isolate, object, index);
} else {
- PropertyAttributes attr;
- return object->GetProperty(*name, &attr);
+ return object->GetProperty(*name);
}
}
@@ -3800,7 +3832,7 @@
// Fast case for string indexing using [] with a smi index.
HandleScope scope(isolate);
Handle<String> str = args.at<String>(0);
- int index = Smi::cast(args[1])->value();
+ int index = args.smi_at(1);
if (index >= 0 && index < str->length()) {
Handle<Object> result = GetCharAt(str, index);
return *result;
@@ -3888,17 +3920,25 @@
if (proto->IsNull()) return *obj_value;
js_object = Handle<JSObject>::cast(proto);
}
- NormalizeElements(js_object);
- Handle<NumberDictionary> dictionary(js_object->element_dictionary());
+ Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
// Make sure that we never go back to fast case.
dictionary->set_requires_slow_elements();
PropertyDetails details = PropertyDetails(attr, NORMAL);
- NumberDictionarySet(dictionary, index, obj_value, details);
+ Handle<NumberDictionary> extended_dictionary =
+ NumberDictionarySet(dictionary, index, obj_value, details);
+ if (*extended_dictionary != *dictionary) {
+ if (js_object->GetElementsKind() ==
+ JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
+ FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
+ } else {
+ js_object->set_elements(*extended_dictionary);
+ }
+ }
return *obj_value;
}
LookupResult result;
- js_object->LookupRealNamedProperty(*name, &result);
+ js_object->LocalLookupRealNamedProperty(*name, &result);
// To be compatible with safari we do not change the value on API objects
// in defineProperty. Firefox disagrees here, and actually changes the value.
@@ -3938,6 +3978,28 @@
}
+// Special case for elements if any of the flags are true.
+// If elements are in fast case we always implicitly assume that:
+// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
+static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
+ Handle<JSObject> js_object,
+ uint32_t index,
+ Handle<Object> value,
+ PropertyAttributes attr) {
+ // Normalize the elements to enable attributes on the property.
+ Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
+ // Make sure that we never go back to fast case.
+ dictionary->set_requires_slow_elements();
+ PropertyDetails details = PropertyDetails(attr, NORMAL);
+ Handle<NumberDictionary> extended_dictionary =
+ NumberDictionarySet(dictionary, index, value, details);
+ if (*extended_dictionary != *dictionary) {
+ js_object->set_elements(*extended_dictionary);
+ }
+ return *value;
+}
+
+
MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
Handle<Object> object,
Handle<Object> key,
@@ -3973,6 +4035,10 @@
return *value;
}
+ if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
+ return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
+ }
+
Handle<Object> result = SetElement(js_object, index, value, strict_mode);
if (result.is_null()) return Failure::Exception();
return *value;
@@ -3981,6 +4047,13 @@
if (key->IsString()) {
Handle<Object> result;
if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
+ if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
+ return NormalizeObjectSetElement(isolate,
+ js_object,
+ index,
+ value,
+ attr);
+ }
result = SetElement(js_object, index, value, strict_mode);
} else {
Handle<String> key_string = Handle<String>::cast(key);
@@ -3998,7 +4071,7 @@
Handle<String> name = Handle<String>::cast(converted);
if (name->AsArrayIndex(&index)) {
- return js_object->SetElement(index, *value, strict_mode);
+ return js_object->SetElement(index, *value, strict_mode, true);
} else {
return js_object->SetProperty(*name, *value, attr, strict_mode);
}
@@ -4026,12 +4099,12 @@
return *value;
}
- return js_object->SetElement(index, *value, kNonStrictMode);
+ return js_object->SetElement(index, *value, kNonStrictMode, true);
}
if (key->IsString()) {
if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
- return js_object->SetElement(index, *value, kNonStrictMode);
+ return js_object->SetElement(index, *value, kNonStrictMode, true);
} else {
Handle<String> key_string = Handle<String>::cast(key);
key_string->TryFlatten();
@@ -4048,7 +4121,7 @@
Handle<String> name = Handle<String>::cast(converted);
if (name->AsArrayIndex(&index)) {
- return js_object->SetElement(index, *value, kNonStrictMode);
+ return js_object->SetElement(index, *value, kNonStrictMode, true);
} else {
return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
}
@@ -4099,7 +4172,7 @@
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]);
+ CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
RUNTIME_ASSERT(
(unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
// Compute attributes.
@@ -4108,7 +4181,7 @@
StrictModeFlag strict_mode = kNonStrictMode;
if (args.length() == 5) {
- CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
+ CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
strict_unchecked == kNonStrictMode);
strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
@@ -4123,10 +4196,10 @@
}
-// Set the ES5 native flag on the function.
+// Set the native flag on the function.
// This is used to decide if we should transform null and undefined
// into the global object when doing call and apply.
-RUNTIME_FUNCTION(MaybeObject*, Runtime_SetES5Flag) {
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
NoHandleAllocation ha;
RUNTIME_ASSERT(args.length() == 1);
@@ -4134,7 +4207,7 @@
if (object->IsJSFunction()) {
JSFunction* func = JSFunction::cast(*object);
- func->shared()->set_es5_native(true);
+ func->shared()->set_native(true);
}
return isolate->heap()->undefined_value();
}
@@ -4169,7 +4242,7 @@
CONVERT_CHECKED(JSObject, object, args[0]);
CONVERT_CHECKED(String, key, args[1]);
- CONVERT_SMI_CHECKED(strict, args[2]);
+ CONVERT_SMI_ARG_CHECKED(strict, 2);
return object->DeleteProperty(key, (strict == kStrictMode)
? JSObject::STRICT_DELETION
: JSObject::NORMAL_DELETION);
@@ -4640,7 +4713,7 @@
}
ASSERT(heap_obj->IsUndefined());
return isolate->heap()->undefined_symbol();
- case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
+ case JS_FUNCTION_TYPE:
return isolate->heap()->function_symbol();
default:
// For any kind of object not handled above, the spec rule for
@@ -5014,6 +5087,8 @@
// Doing JSON quoting cannot make the string more than this many times larger.
static const int kJsonQuoteWorstCaseBlowup = 6;
+static const int kSpaceForQuotesAndComma = 3;
+static const int kSpaceForBrackets = 2;
// Covers the entire ASCII range (all other characters are unchanged by JSON
// quoting).
@@ -5101,13 +5176,51 @@
}
+template <typename SinkChar, typename SourceChar>
+static inline SinkChar* WriteQuoteJsonString(
+ Isolate* isolate,
+ SinkChar* write_cursor,
+ Vector<const SourceChar> characters) {
+ // SinkChar is only char if SourceChar is guaranteed to be char.
+ ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
+ const SourceChar* read_cursor = characters.start();
+ const SourceChar* end = read_cursor + characters.length();
+ *(write_cursor++) = '"';
+ while (read_cursor < end) {
+ SourceChar c = *(read_cursor++);
+ if (sizeof(SourceChar) > 1u &&
+ static_cast<unsigned>(c) >= kQuoteTableLength) {
+ *(write_cursor++) = static_cast<SinkChar>(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++) = '"';
+ return write_cursor;
+}
+
+
template <typename Char, typename StringType, bool comma>
static MaybeObject* QuoteJsonString(Isolate* isolate,
Vector<const Char> characters) {
int length = characters.length();
isolate->counters()->quote_json_char_count()->Increment(length);
- const int kSpaceForQuotes = 2 + (comma ? 1 :0);
- int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
+ int worst_case_length =
+ length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
if (worst_case_length > kMaxGuaranteedNewSpaceString) {
return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
}
@@ -5132,34 +5245,9 @@
Char* write_cursor = reinterpret_cast<Char*>(
new_string->address() + SeqAsciiString::kHeaderSize);
if (comma) *(write_cursor++) = ',';
- *(write_cursor++) = '"';
-
- const Char* read_cursor = characters.start();
- 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++) = '"';
-
+ write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
+ write_cursor,
+ characters);
int final_length = static_cast<int>(
write_cursor - reinterpret_cast<Char*>(
new_string->address() + SeqAsciiString::kHeaderSize));
@@ -5213,11 +5301,106 @@
}
}
+
+template <typename Char, typename StringType>
+static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
+ FixedArray* array,
+ int worst_case_length) {
+ int length = array->length();
+
+ MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
+ worst_case_length);
+ Object* new_object;
+ if (!new_alloc->ToObject(&new_object)) {
+ return new_alloc;
+ }
+ if (!isolate->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 isolate->heap()->undefined_value();
+ }
+ AssertNoAllocation no_gc;
+ StringType* new_string = StringType::cast(new_object);
+ ASSERT(isolate->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++) = '[';
+ for (int i = 0; i < length; i++) {
+ if (i != 0) *(write_cursor++) = ',';
+ String* str = String::cast(array->get(i));
+ if (str->IsTwoByteRepresentation()) {
+ write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
+ write_cursor,
+ str->ToUC16Vector());
+ } else {
+ write_cursor = WriteQuoteJsonString<Char, char>(isolate,
+ write_cursor,
+ str->ToAsciiVector());
+ }
+ }
+ *(write_cursor++) = ']';
+
+ int final_length = static_cast<int>(
+ write_cursor - reinterpret_cast<Char*>(
+ new_string->address() + SeqAsciiString::kHeaderSize));
+ isolate->heap()->new_space()->
+ template ShrinkStringAtAllocationBoundary<StringType>(
+ new_string, final_length);
+ return new_string;
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 1);
+ CONVERT_CHECKED(JSArray, array, args[0]);
+
+ if (!array->HasFastElements()) return isolate->heap()->undefined_value();
+ FixedArray* elements = FixedArray::cast(array->elements());
+ int n = elements->length();
+ bool ascii = true;
+ int total_length = 0;
+
+ for (int i = 0; i < n; i++) {
+ Object* elt = elements->get(i);
+ if (!elt->IsString()) return isolate->heap()->undefined_value();
+ String* element = String::cast(elt);
+ if (!element->IsFlat()) return isolate->heap()->undefined_value();
+ total_length += element->length();
+ if (ascii && element->IsTwoByteRepresentation()) {
+ ascii = false;
+ }
+ }
+
+ int worst_case_length =
+ kSpaceForBrackets + n * kSpaceForQuotesAndComma
+ + total_length * kJsonQuoteWorstCaseBlowup;
+
+ if (worst_case_length > kMaxGuaranteedNewSpaceString) {
+ return isolate->heap()->undefined_value();
+ }
+
+ if (ascii) {
+ return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
+ elements,
+ worst_case_length);
+ } else {
+ return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
+ elements,
+ worst_case_length);
+ }
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
NoHandleAllocation ha;
CONVERT_CHECKED(String, s, args[0]);
- CONVERT_SMI_CHECKED(radix, args[1]);
+ CONVERT_SMI_ARG_CHECKED(radix, 1);
s->TryFlatten();
@@ -5564,6 +5747,27 @@
}
+void FindAsciiStringIndices(Vector<const char> subject,
+ char pattern,
+ ZoneList<int>* indices,
+ unsigned int limit) {
+ ASSERT(limit > 0);
+ // Collect indices of pattern in subject using memchr.
+ // Stop after finding at most limit values.
+ const char* subject_start = reinterpret_cast<const char*>(subject.start());
+ const char* subject_end = subject_start + subject.length();
+ const char* pos = subject_start;
+ while (limit > 0) {
+ pos = reinterpret_cast<const char*>(
+ memchr(pos, pattern, subject_end - pos));
+ if (pos == NULL) return;
+ indices->Add(static_cast<int>(pos - subject_start));
+ pos++;
+ limit--;
+ }
+}
+
+
template <typename SubjectChar, typename PatternChar>
void FindStringIndices(Isolate* isolate,
Vector<const SubjectChar> subject,
@@ -5571,11 +5775,11 @@
ZoneList<int>* indices,
unsigned int limit) {
ASSERT(limit > 0);
- // Collect indices of pattern in subject, and the end-of-string index.
+ // Collect indices of pattern in subject.
// Stop after finding at most limit values.
- StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
int pattern_length = pattern.length();
int index = 0;
+ StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
while (limit > 0) {
index = search.Search(subject, index);
if (index < 0) return;
@@ -5618,11 +5822,19 @@
if (subject->IsAsciiRepresentation()) {
Vector<const char> subject_vector = subject->ToAsciiVector();
if (pattern->IsAsciiRepresentation()) {
- FindStringIndices(isolate,
- subject_vector,
- pattern->ToAsciiVector(),
- &indices,
- limit);
+ Vector<const char> pattern_vector = pattern->ToAsciiVector();
+ if (pattern_vector.length() == 1) {
+ FindAsciiStringIndices(subject_vector,
+ pattern_vector[0],
+ &indices,
+ limit);
+ } else {
+ FindStringIndices(isolate,
+ subject_vector,
+ pattern_vector,
+ &indices,
+ limit);
+ }
} else {
FindStringIndices(isolate,
subject_vector,
@@ -5673,7 +5885,7 @@
HandleScope local_loop_handle;
int part_end = indices.at(i);
Handle<String> substring =
- isolate->factory()->NewSubString(subject, part_start, part_end);
+ isolate->factory()->NewProperSubString(subject, part_start, part_end);
elements->set(i, *substring);
part_start = part_end + pattern_length;
}
@@ -5806,7 +6018,7 @@
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- CONVERT_DOUBLE_CHECKED(number, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(number, 0);
// We do not include 0 so that we don't have to treat +0 / -0 cases.
if (number > 0 && number <= Smi::kMaxValue) {
@@ -5820,7 +6032,7 @@
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- CONVERT_DOUBLE_CHECKED(number, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(number, 0);
// We do not include 0 so that we don't have to treat +0 / -0 cases.
if (number > 0 && number <= Smi::kMaxValue) {
@@ -5848,7 +6060,7 @@
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- CONVERT_DOUBLE_CHECKED(number, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(number, 0);
// We do not include 0 so that we don't have to treat +0 / -0 cases.
if (number > 0 && number <= Smi::kMaxValue) {
@@ -5890,8 +6102,8 @@
NoHandleAllocation ha;
ASSERT(args.length() == 2);
- CONVERT_DOUBLE_CHECKED(x, args[0]);
- CONVERT_DOUBLE_CHECKED(y, args[1]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+ CONVERT_DOUBLE_ARG_CHECKED(y, 1);
return isolate->heap()->NumberFromDouble(x + y);
}
@@ -5900,8 +6112,8 @@
NoHandleAllocation ha;
ASSERT(args.length() == 2);
- CONVERT_DOUBLE_CHECKED(x, args[0]);
- CONVERT_DOUBLE_CHECKED(y, args[1]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+ CONVERT_DOUBLE_ARG_CHECKED(y, 1);
return isolate->heap()->NumberFromDouble(x - y);
}
@@ -5910,8 +6122,8 @@
NoHandleAllocation ha;
ASSERT(args.length() == 2);
- CONVERT_DOUBLE_CHECKED(x, args[0]);
- CONVERT_DOUBLE_CHECKED(y, args[1]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+ CONVERT_DOUBLE_ARG_CHECKED(y, 1);
return isolate->heap()->NumberFromDouble(x * y);
}
@@ -5920,7 +6132,7 @@
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return isolate->heap()->NumberFromDouble(-x);
}
@@ -5937,8 +6149,8 @@
NoHandleAllocation ha;
ASSERT(args.length() == 2);
- CONVERT_DOUBLE_CHECKED(x, args[0]);
- CONVERT_DOUBLE_CHECKED(y, args[1]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+ CONVERT_DOUBLE_ARG_CHECKED(y, 1);
return isolate->heap()->NumberFromDouble(x / y);
}
@@ -5947,8 +6159,8 @@
NoHandleAllocation ha;
ASSERT(args.length() == 2);
- CONVERT_DOUBLE_CHECKED(x, args[0]);
- CONVERT_DOUBLE_CHECKED(y, args[1]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+ CONVERT_DOUBLE_ARG_CHECKED(y, 1);
x = modulo(x, y);
// NumberFromDouble may return a Smi instead of a Number object
@@ -6013,7 +6225,7 @@
isolate->context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
- int array_length = Smi::cast(args[1])->value();
+ int array_length = args.smi_at(1);
CONVERT_CHECKED(String, special, args[2]);
// This assumption is used by the slice encoding in one or two smis.
@@ -6126,7 +6338,7 @@
isolate->context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
- int array_length = Smi::cast(args[1])->value();
+ int array_length = args.smi_at(1);
CONVERT_CHECKED(String, separator, args[2]);
if (!array->HasFastElements()) {
@@ -6404,8 +6616,8 @@
NoHandleAllocation ha;
ASSERT(args.length() == 2);
- CONVERT_DOUBLE_CHECKED(x, args[0]);
- CONVERT_DOUBLE_CHECKED(y, args[1]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+ CONVERT_DOUBLE_ARG_CHECKED(y, 1);
if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
if (x == y) return Smi::FromInt(EQUAL);
@@ -6441,8 +6653,8 @@
NoHandleAllocation ha;
ASSERT(args.length() == 3);
- CONVERT_DOUBLE_CHECKED(x, args[0]);
- CONVERT_DOUBLE_CHECKED(y, args[1]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+ CONVERT_DOUBLE_ARG_CHECKED(y, 1);
if (isnan(x) || isnan(y)) return args[2];
if (x == y) return Smi::FromInt(EQUAL);
if (isless(x, y)) return Smi::FromInt(LESS);
@@ -6465,50 +6677,69 @@
// If the integers are equal so are the string representations.
if (x_value == y_value) return Smi::FromInt(EQUAL);
- // If one of the integers are zero the normal integer order is the
+ // If one of the integers is zero the normal integer order is the
// same as the lexicographic order of the string representations.
- if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
+ if (x_value == 0 || y_value == 0)
+ return Smi::FromInt(x_value < y_value ? LESS : GREATER);
// If only one of the integers is negative the negative number is
// smallest because the char code of '-' is less than the char code
// of any digit. Otherwise, we make both values positive.
+
+ // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
+ // architectures using 32-bit Smis.
+ uint32_t x_scaled = x_value;
+ uint32_t y_scaled = y_value;
if (x_value < 0 || y_value < 0) {
if (y_value >= 0) return Smi::FromInt(LESS);
if (x_value >= 0) return Smi::FromInt(GREATER);
- x_value = -x_value;
- y_value = -y_value;
+ x_scaled = -x_value;
+ y_scaled = -y_value;
}
- // Arrays for the individual characters of the two Smis. Smis are
- // 31 bit integers and 10 decimal digits are therefore enough.
- // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
- int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
- int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
+ static const uint32_t kPowersOf10[] = {
+ 1, 10, 100, 1000, 10*1000, 100*1000,
+ 1000*1000, 10*1000*1000, 100*1000*1000,
+ 1000*1000*1000
+ };
+ // If the integers have the same number of decimal digits they can be
+ // compared directly as the numeric order is the same as the
+ // lexicographic order. If one integer has fewer digits, it is scaled
+ // by some power of 10 to have the same number of digits as the longer
+ // integer. If the scaled integers are equal it means the shorter
+ // integer comes first in the lexicographic order.
- // Convert the integers to arrays of their decimal digits.
- int x_index = 0;
- int y_index = 0;
- while (x_value > 0) {
- x_elms[x_index++] = x_value % 10;
- x_value /= 10;
- }
- while (y_value > 0) {
- y_elms[y_index++] = y_value % 10;
- y_value /= 10;
- }
+ // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
+ int x_log2 = IntegerLog2(x_scaled);
+ int x_log10 = ((x_log2 + 1) * 1233) >> 12;
+ x_log10 -= x_scaled < kPowersOf10[x_log10];
- // Loop through the arrays of decimal digits finding the first place
- // where they differ.
- while (--x_index >= 0 && --y_index >= 0) {
- int diff = x_elms[x_index] - y_elms[y_index];
- if (diff != 0) return Smi::FromInt(diff);
+ int y_log2 = IntegerLog2(y_scaled);
+ int y_log10 = ((y_log2 + 1) * 1233) >> 12;
+ y_log10 -= y_scaled < kPowersOf10[y_log10];
+
+ int tie = EQUAL;
+
+ if (x_log10 < y_log10) {
+ // X has fewer digits. We would like to simply scale up X but that
+ // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
+ // be scaled up to 9_000_000_000. So we scale up by the next
+ // smallest power and scale down Y to drop one digit. It is OK to
+ // drop one digit from the longer integer since the final digit is
+ // past the length of the shorter integer.
+ x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
+ y_scaled /= 10;
+ tie = LESS;
+ } else if (y_log10 < x_log10) {
+ y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
+ x_scaled /= 10;
+ tie = GREATER;
}
- // If one array is a suffix of the other array, the longest array is
- // the representation of the largest of the Smis in the
- // lexicographic ordering.
- return Smi::FromInt(x_index - y_index);
+ if (x_scaled < y_scaled) return Smi::FromInt(LESS);
+ if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
+ return Smi::FromInt(tie);
}
@@ -6615,7 +6846,7 @@
ASSERT(args.length() == 1);
isolate->counters()->math_acos()->Increment();
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
}
@@ -6625,7 +6856,7 @@
ASSERT(args.length() == 1);
isolate->counters()->math_asin()->Increment();
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
}
@@ -6635,7 +6866,7 @@
ASSERT(args.length() == 1);
isolate->counters()->math_atan()->Increment();
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
}
@@ -6648,8 +6879,8 @@
ASSERT(args.length() == 2);
isolate->counters()->math_atan2()->Increment();
- CONVERT_DOUBLE_CHECKED(x, args[0]);
- CONVERT_DOUBLE_CHECKED(y, args[1]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+ CONVERT_DOUBLE_ARG_CHECKED(y, 1);
double result;
if (isinf(x) && isinf(y)) {
// Make sure that the result in case of two infinite arguments
@@ -6671,7 +6902,7 @@
ASSERT(args.length() == 1);
isolate->counters()->math_ceil()->Increment();
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return isolate->heap()->NumberFromDouble(ceiling(x));
}
@@ -6681,7 +6912,7 @@
ASSERT(args.length() == 1);
isolate->counters()->math_cos()->Increment();
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
}
@@ -6691,7 +6922,7 @@
ASSERT(args.length() == 1);
isolate->counters()->math_exp()->Increment();
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
}
@@ -6701,7 +6932,7 @@
ASSERT(args.length() == 1);
isolate->counters()->math_floor()->Increment();
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return isolate->heap()->NumberFromDouble(floor(x));
}
@@ -6711,7 +6942,7 @@
ASSERT(args.length() == 1);
isolate->counters()->math_log()->Increment();
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
}
@@ -6721,16 +6952,16 @@
ASSERT(args.length() == 2);
isolate->counters()->math_pow()->Increment();
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
// If the second argument is a smi, it is much faster to call the
// custom powi() function than the generic pow().
if (args[1]->IsSmi()) {
- int y = Smi::cast(args[1])->value();
+ int y = args.smi_at(1);
return isolate->heap()->NumberFromDouble(power_double_int(x, y));
}
- CONVERT_DOUBLE_CHECKED(y, args[1]);
+ CONVERT_DOUBLE_ARG_CHECKED(y, 1);
return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
}
@@ -6739,8 +6970,8 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
- CONVERT_DOUBLE_CHECKED(x, args[0]);
- CONVERT_DOUBLE_CHECKED(y, args[1]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+ CONVERT_DOUBLE_ARG_CHECKED(y, 1);
if (y == 0) {
return Smi::FromInt(1);
} else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
@@ -6799,7 +7030,7 @@
ASSERT(args.length() == 1);
isolate->counters()->math_sin()->Increment();
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
}
@@ -6809,7 +7040,7 @@
ASSERT(args.length() == 1);
isolate->counters()->math_sqrt()->Increment();
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return isolate->heap()->AllocateHeapNumber(sqrt(x));
}
@@ -6819,7 +7050,7 @@
ASSERT(args.length() == 1);
isolate->counters()->math_tan()->Increment();
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
}
@@ -6873,9 +7104,9 @@
NoHandleAllocation ha;
ASSERT(args.length() == 3);
- CONVERT_SMI_CHECKED(year, args[0]);
- CONVERT_SMI_CHECKED(month, args[1]);
- CONVERT_SMI_CHECKED(date, args[2]);
+ CONVERT_SMI_ARG_CHECKED(year, 0);
+ CONVERT_SMI_ARG_CHECKED(month, 1);
+ CONVERT_SMI_ARG_CHECKED(date, 2);
return Smi::FromInt(MakeDay(year, month, date));
}
@@ -7172,7 +7403,7 @@
NoHandleAllocation ha;
ASSERT(args.length() == 2);
- CONVERT_DOUBLE_CHECKED(t, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(t, 0);
CONVERT_CHECKED(JSArray, res_array, args[1]);
int year, month, day;
@@ -7192,12 +7423,109 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 3);
+
+ Handle<JSFunction> callee = args.at<JSFunction>(0);
+ Object** parameters = reinterpret_cast<Object**>(args[1]);
+ const int argument_count = Smi::cast(args[2])->value();
+
+ Handle<JSObject> result =
+ isolate->factory()->NewArgumentsObject(callee, argument_count);
+ // Allocate the elements if needed.
+ int parameter_count = callee->shared()->formal_parameter_count();
+ if (argument_count > 0) {
+ if (parameter_count > 0) {
+ int mapped_count = Min(argument_count, parameter_count);
+ Handle<FixedArray> parameter_map =
+ isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
+ parameter_map->set_map(
+ isolate->heap()->non_strict_arguments_elements_map());
+
+ Handle<Map> old_map(result->map());
+ Handle<Map> new_map =
+ isolate->factory()->CopyMapDropTransitions(old_map);
+ new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
+
+ result->set_map(*new_map);
+ result->set_elements(*parameter_map);
+
+ // Store the context and the arguments array at the beginning of the
+ // parameter map.
+ Handle<Context> context(isolate->context());
+ Handle<FixedArray> arguments =
+ isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
+ parameter_map->set(0, *context);
+ parameter_map->set(1, *arguments);
+
+ // Loop over the actual parameters backwards.
+ int index = argument_count - 1;
+ while (index >= mapped_count) {
+ // These go directly in the arguments array and have no
+ // corresponding slot in the parameter map.
+ arguments->set(index, *(parameters - index - 1));
+ --index;
+ }
+
+ ScopeInfo<> scope_info(callee->shared()->scope_info());
+ while (index >= 0) {
+ // Detect duplicate names to the right in the parameter list.
+ Handle<String> name = scope_info.parameter_name(index);
+ int context_slot_count = scope_info.number_of_context_slots();
+ bool duplicate = false;
+ for (int j = index + 1; j < parameter_count; ++j) {
+ if (scope_info.parameter_name(j).is_identical_to(name)) {
+ duplicate = true;
+ break;
+ }
+ }
+
+ if (duplicate) {
+ // This goes directly in the arguments array with a hole in the
+ // parameter map.
+ arguments->set(index, *(parameters - index - 1));
+ parameter_map->set_the_hole(index + 2);
+ } else {
+ // The context index goes in the parameter map with a hole in the
+ // arguments array.
+ int context_index = -1;
+ for (int j = Context::MIN_CONTEXT_SLOTS;
+ j < context_slot_count;
+ ++j) {
+ if (scope_info.context_slot_name(j).is_identical_to(name)) {
+ context_index = j;
+ break;
+ }
+ }
+ ASSERT(context_index >= 0);
+ arguments->set_the_hole(index);
+ parameter_map->set(index + 2, Smi::FromInt(context_index));
+ }
+
+ --index;
+ }
+ } else {
+ // If there is no aliasing, the arguments object elements are not
+ // special in any way.
+ Handle<FixedArray> elements =
+ isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
+ result->set_elements(*elements);
+ for (int i = 0; i < argument_count; ++i) {
+ elements->set(i, *(parameters - i - 1));
+ }
+ }
+ }
+ return *result;
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
NoHandleAllocation ha;
ASSERT(args.length() == 3);
JSFunction* callee = JSFunction::cast(args[0]);
Object** parameters = reinterpret_cast<Object**>(args[1]);
- const int length = Smi::cast(args[2])->value();
+ const int length = args.smi_at(2);
Object* result;
{ MaybeObject* maybe_result =
@@ -7234,10 +7562,8 @@
CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
- // Allocate global closures in old space and allocate local closures
- // in new space. Additionally pretenure closures that are assigned
+ // The caller ensures that we pretenure closures that are assigned
// directly to properties.
- pretenure = pretenure || (context->global_context() == *context);
PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
Handle<JSFunction> result =
isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
@@ -7357,7 +7683,7 @@
// If function should not have prototype, construction is not allowed. In this
// case generated code bailouts here, since function has no initial_map.
- if (!function->should_have_prototype()) {
+ if (!function->should_have_prototype() && !function->shared()->bound()) {
Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
Handle<Object> type_error =
isolate->factory()->NewTypeError("not_constructor", arguments);
@@ -7498,7 +7824,7 @@
ASSERT(args.length() == 1);
RUNTIME_ASSERT(args[0]->IsSmi());
Deoptimizer::BailoutType type =
- static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
+ static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
ASSERT(isolate->heap()->IsAllocationAllowed());
int frames = deoptimizer->output_count();
@@ -7529,7 +7855,6 @@
}
}
- isolate->compilation_cache()->MarkForLazyOptimizing(function);
if (type == Deoptimizer::EAGER) {
RUNTIME_ASSERT(function->IsOptimized());
} else {
@@ -7585,6 +7910,15 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
+#if defined(USE_SIMULATOR)
+ return isolate->heap()->true_value();
+#else
+ return isolate->heap()->false_value();
+#endif
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
@@ -7624,7 +7958,7 @@
CONVERT_ARG_CHECKED(JSFunction, function, 0);
// We're not prepared to handle a function with arguments object.
- ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
+ ASSERT(!function->shared()->uses_arguments());
// We have hit a back edge in an unoptimized frame for a function that was
// selected for on-stack replacement. Find the unoptimized code object.
@@ -7748,7 +8082,7 @@
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
+RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -7766,50 +8100,73 @@
}
-MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
- Object* object,
- bool is_catch_context) {
- // Convert the object to a proper JavaScript object.
- Object* js_object = object;
- if (!js_object->IsJSObject()) {
- MaybeObject* maybe_js_object = js_object->ToObject();
- if (!maybe_js_object->ToObject(&js_object)) {
- if (!Failure::cast(maybe_js_object)->IsInternalError()) {
+RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 2);
+ JSObject* extension_object;
+ if (args[0]->IsJSObject()) {
+ extension_object = JSObject::cast(args[0]);
+ } else {
+ // Convert the object to a proper JavaScript object.
+ MaybeObject* maybe_js_object = args[0]->ToObject();
+ if (!maybe_js_object->To(&extension_object)) {
+ if (Failure::cast(maybe_js_object)->IsInternalError()) {
+ HandleScope scope(isolate);
+ Handle<Object> handle = args.at<Object>(0);
+ Handle<Object> result =
+ isolate->factory()->NewTypeError("with_expression",
+ HandleVector(&handle, 1));
+ return isolate->Throw(*result);
+ } else {
return maybe_js_object;
}
- HandleScope scope(isolate);
- Handle<Object> handle(object, isolate);
- Handle<Object> result =
- isolate->factory()->NewTypeError("with_expression",
- HandleVector(&handle, 1));
- return isolate->Throw(*result);
}
}
- Object* result;
- { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
- isolate->context(), JSObject::cast(js_object), is_catch_context);
- if (!maybe_result->ToObject(&result)) return maybe_result;
+ JSFunction* function;
+ if (args[1]->IsSmi()) {
+ // A smi sentinel indicates a context nested inside global code rather
+ // than some function. There is a canonical empty function that can be
+ // gotten from the global context.
+ function = isolate->context()->global_context()->closure();
+ } else {
+ function = JSFunction::cast(args[1]);
}
- Context* context = Context::cast(result);
+ Context* context;
+ MaybeObject* maybe_context =
+ isolate->heap()->AllocateWithContext(function,
+ isolate->context(),
+ extension_object);
+ if (!maybe_context->To(&context)) return maybe_context;
isolate->set_context(context);
-
- return result;
+ return context;
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
- NoHandleAllocation ha;
- ASSERT(args.length() == 1);
- return PushContextHelper(isolate, args[0], false);
-}
-
-
RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
NoHandleAllocation ha;
- ASSERT(args.length() == 1);
- return PushContextHelper(isolate, args[0], true);
+ ASSERT(args.length() == 3);
+ String* name = String::cast(args[0]);
+ Object* thrown_object = args[1];
+ JSFunction* function;
+ if (args[2]->IsSmi()) {
+ // A smi sentinel indicates a context nested inside global code rather
+ // than some function. There is a canonical empty function that can be
+ // gotten from the global context.
+ function = isolate->context()->global_context()->closure();
+ } else {
+ function = JSFunction::cast(args[2]);
+ }
+ Context* context;
+ MaybeObject* maybe_context =
+ isolate->heap()->AllocateCatchContext(function,
+ isolate->context(),
+ name,
+ thrown_object);
+ if (!maybe_context->To(&context)) return maybe_context;
+ isolate->set_context(context);
+ return context;
}
@@ -7999,7 +8356,7 @@
Handle<Object> value(args[0], isolate);
CONVERT_ARG_CHECKED(Context, context, 1);
CONVERT_ARG_CHECKED(String, name, 2);
- CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
+ CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
strict_unchecked == kNonStrictMode);
StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
@@ -8313,7 +8670,7 @@
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
const char* zone = OS::LocalTimezone(x);
return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
}
@@ -8331,7 +8688,7 @@
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- CONVERT_DOUBLE_CHECKED(x, args[0]);
+ CONVERT_DOUBLE_ARG_CHECKED(x, 0);
return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
}
@@ -8349,7 +8706,14 @@
ASSERT_EQ(1, args.length());
CONVERT_ARG_CHECKED(String, source, 0);
- Handle<Object> result = JsonParser::Parse(source);
+ source = Handle<String>(source->TryFlattenGetString());
+ // Optimized fast case where we only have ascii characters.
+ Handle<Object> result;
+ if (source->IsSeqAsciiString()) {
+ result = JsonParser<true>::Parse(source);
+ } else {
+ result = JsonParser<false>::Parse(source);
+ }
if (result.is_null()) {
// Syntax error or stack overflow in scanner.
ASSERT(isolate->has_pending_exception());
@@ -8465,12 +8829,7 @@
// Stop search when eval is found or when the global context is
// reached.
if (attributes != ABSENT || context->IsGlobalContext()) break;
- if (context->is_function_context()) {
- context = Handle<Context>(Context::cast(context->closure()->context()),
- isolate);
- } else {
- context = Handle<Context>(context->previous(), isolate);
- }
+ context = Handle<Context>(context->previous(), isolate);
}
// If eval could not be resolved, it has been deleted and we need to
@@ -8503,8 +8862,7 @@
return CompileGlobalEval(isolate,
args.at<String>(1),
args.at<Object>(2),
- static_cast<StrictModeFlag>(
- Smi::cast(args[3])->value()));
+ static_cast<StrictModeFlag>(args.smi_at(3)));
}
@@ -8525,8 +8883,7 @@
return CompileGlobalEval(isolate,
args.at<String>(1),
args.at<Object>(2),
- static_cast<StrictModeFlag>(
- Smi::cast(args[3])->value()));
+ static_cast<StrictModeFlag>(args.smi_at(3)));
}
@@ -8587,8 +8944,8 @@
}
Object* obj;
// Strict not needed. Used for cycle detection in Array join implementation.
- { MaybeObject* maybe_obj = array->SetFastElement(length, element,
- kNonStrictMode);
+ { MaybeObject* maybe_obj =
+ array->SetFastElement(length, element, kNonStrictMode, true);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
return isolate->heap()->true_value();
@@ -9614,7 +9971,10 @@
// If there is no JavaScript stack frame count is 0.
return Smi::FromInt(0);
}
- for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
+
+ for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
+ n += it.frame()->GetInlineCount();
+ }
return Smi::FromInt(n);
}
@@ -9627,7 +9987,7 @@
static const int kFrameDetailsSourcePositionIndex = 5;
static const int kFrameDetailsConstructCallIndex = 6;
static const int kFrameDetailsAtReturnIndex = 7;
-static const int kFrameDetailsDebuggerFrameIndex = 8;
+static const int kFrameDetailsFlagsIndex = 8;
static const int kFrameDetailsFirstDynamicIndex = 9;
// Return an array with frame details
@@ -9643,7 +10003,7 @@
// 5: Source position
// 6: Constructor call
// 7: Is at return
-// 8: Debugger frame
+// 8: Flags
// Arguments name, value
// Locals name, value
// Return value if any
@@ -9666,16 +10026,26 @@
// If there are no JavaScript stack frames return undefined.
return heap->undefined_value();
}
+
+ int deoptimized_frame_index = -1; // Frame index in optimized frame.
+ DeoptimizedFrameInfo* deoptimized_frame = NULL;
+
int count = 0;
JavaScriptFrameIterator it(isolate, id);
for (; !it.done(); it.Advance()) {
- if (count == index) break;
- count++;
+ if (index < count + it.frame()->GetInlineCount()) break;
+ count += it.frame()->GetInlineCount();
}
if (it.done()) return heap->undefined_value();
- bool is_optimized_frame =
- it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
+ if (it.frame()->is_optimized()) {
+ deoptimized_frame_index =
+ it.frame()->GetInlineCount() - (index - count) - 1;
+ deoptimized_frame = Deoptimizer::DebuggerInspectableFrame(
+ it.frame(),
+ deoptimized_frame_index,
+ isolate);
+ }
// Traverse the saved contexts chain to find the active context for the
// selected frame.
@@ -9692,17 +10062,17 @@
int position =
it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
- // Check for constructor frame.
- bool constructor = it.frame()->IsConstructor();
+ // Check for constructor frame. Inlined frames cannot be construct calls.
+ bool inlined_frame =
+ it.frame()->is_optimized() && deoptimized_frame_index != 0;
+ bool constructor = !inlined_frame && it.frame()->IsConstructor();
// Get scope info and read from it for local variable information.
Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
+ ASSERT(*scope_info != SerializedScopeInfo::Empty());
ScopeInfo<> info(*scope_info);
- // Get the context.
- Handle<Context> context(Context::cast(it.frame()->context()));
-
// Get the locals names and values into a temporary array.
//
// TODO(1240907): Hide compiler-introduced stack variables
@@ -9711,31 +10081,27 @@
Handle<FixedArray> locals =
isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
- // Fill in the names of the locals.
- for (int i = 0; i < info.NumberOfLocals(); i++) {
+ // Fill in the values of the locals.
+ int i = 0;
+ for (; i < info.number_of_stack_slots(); ++i) {
+ // Use the value from the stack.
locals->set(i * 2, *info.LocalName(i));
- }
-
- // Fill in the values of the locals.
- for (int i = 0; i < info.NumberOfLocals(); i++) {
- if (is_optimized_frame) {
- // If we are inspecting an optimized frame use undefined as the
- // value for all locals.
- //
- // TODO(1140): We should be able to get the correct values
- // for locals in optimized frames.
- locals->set(i * 2 + 1, isolate->heap()->undefined_value());
- } else if (i < info.number_of_stack_slots()) {
+ if (it.frame()->is_optimized()) {
+ // Get the value from the deoptimized frame.
+ locals->set(i * 2 + 1,
+ deoptimized_frame->GetExpression(i));
+ } else {
// Get the value from the stack.
locals->set(i * 2 + 1, it.frame()->GetExpression(i));
- } else {
- // Traverse the context chain to the function context as all local
- // variables stored in the context will be on the function context.
+ }
+ }
+ if (i < info.NumberOfLocals()) {
+ // Get the context containing declarations.
+ Handle<Context> context(
+ Context::cast(it.frame()->context())->declaration_context());
+ for (; i < info.NumberOfLocals(); ++i) {
Handle<String> name = info.LocalName(i);
- while (!context->is_function_context()) {
- context = Handle<Context>(context->previous());
- }
- ASSERT(context->is_function_context());
+ locals->set(i * 2, *name);
locals->set(i * 2 + 1,
context->get(scope_info->ContextSlotIndex(*name, NULL)));
}
@@ -9744,7 +10110,7 @@
// Check whether this frame is positioned at return. If not top
// frame or if the frame is optimized it cannot be at a return.
bool at_return = false;
- if (!is_optimized_frame && index == 0) {
+ if (!it.frame()->is_optimized() && index == 0) {
at_return = isolate->debug()->IsBreakAtReturn(it.frame());
}
@@ -9789,8 +10155,12 @@
// Find the number of arguments to fill. At least fill the number of
// parameters for the function and fill more if more parameters are provided.
int argument_count = info.number_of_parameters();
- if (argument_count < it.frame()->ComputeParametersCount()) {
- argument_count = it.frame()->ComputeParametersCount();
+ if (it.frame()->is_optimized()) {
+ ASSERT_EQ(argument_count, deoptimized_frame->parameters_count());
+ } else {
+ if (argument_count < it.frame()->ComputeParametersCount()) {
+ argument_count = it.frame()->ComputeParametersCount();
+ }
}
// Calculate the size of the result.
@@ -9803,7 +10173,13 @@
details->set(kFrameDetailsFrameIdIndex, *frame_id);
// Add the function (same as in function frame).
- details->set(kFrameDetailsFunctionIndex, it.frame()->function());
+ if (it.frame()->is_optimized()) {
+ // Get the function from the deoptimized frame.
+ details->set(kFrameDetailsFunctionIndex, deoptimized_frame->GetFunction());
+ } else {
+ // Get the function from the stack.
+ details->set(kFrameDetailsFunctionIndex, it.frame()->function());
+ }
// Add the arguments count.
details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
@@ -9825,10 +10201,21 @@
// Add the at return information.
details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
- // Add information on whether this frame is invoked in the debugger context.
- details->set(kFrameDetailsDebuggerFrameIndex,
- heap->ToBoolean(*save->context() ==
- *isolate->debug()->debug_context()));
+ // Add flags to indicate information on whether this frame is
+ // bit 0: invoked in the debugger context.
+ // bit 1: optimized frame.
+ // bit 2: inlined in optimized frame
+ int flags = 0;
+ if (*save->context() == *isolate->debug()->debug_context()) {
+ flags |= 1 << 0;
+ }
+ if (it.frame()->is_optimized()) {
+ flags |= 1 << 1;
+ if (deoptimized_frame_index > 0) {
+ flags |= 1 << 2;
+ }
+ }
+ details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
// Fill the dynamic part.
int details_index = kFrameDetailsFirstDynamicIndex;
@@ -9842,16 +10229,17 @@
details->set(details_index++, heap->undefined_value());
}
- // Parameter value. If we are inspecting an optimized frame, use
- // undefined as the value.
- //
- // TODO(3141533): We should be able to get the actual parameter
- // value for optimized frames.
- if (!is_optimized_frame &&
- (i < it.frame()->ComputeParametersCount())) {
- details->set(details_index++, it.frame()->GetParameter(i));
+ // Parameter value.
+ if (it.frame()->is_optimized()) {
+ // Get the value from the deoptimized frame.
+ details->set(details_index++, deoptimized_frame->GetParameter(i));
} else {
- details->set(details_index++, heap->undefined_value());
+ if (i < it.frame()->ComputeParametersCount()) {
+ // Get the value from the stack.
+ details->set(details_index++, it.frame()->GetParameter(i));
+ } else {
+ details->set(details_index++, heap->undefined_value());
+ }
}
}
@@ -9883,6 +10271,12 @@
}
details->set(kFrameDetailsReceiverIndex, *receiver);
+ // Get rid of the calculated deoptimized frame if any.
+ if (deoptimized_frame != NULL) {
+ Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame,
+ isolate);
+ }
+
ASSERT_EQ(details_size, details_index);
return *isolate->factory()->NewJSArrayWithElements(details);
}
@@ -9902,18 +10296,14 @@
int context_index = serialized_scope_info->ContextSlotIndex(
*scope_info.context_slot_name(i), NULL);
- // Don't include the arguments shadow (.arguments) context variable.
- if (*scope_info.context_slot_name(i) !=
- isolate->heap()->arguments_shadow_symbol()) {
- RETURN_IF_EMPTY_HANDLE_VALUE(
- isolate,
- SetProperty(scope_object,
- scope_info.context_slot_name(i),
- Handle<Object>(context->get(context_index), isolate),
- NONE,
- kNonStrictMode),
- false);
- }
+ RETURN_IF_EMPTY_HANDLE_VALUE(
+ isolate,
+ SetProperty(scope_object,
+ scope_info.context_slot_name(i),
+ Handle<Object>(context->get(context_index), isolate),
+ NONE,
+ kNonStrictMode),
+ false);
}
return true;
@@ -9947,7 +10337,7 @@
}
// Second fill all stack locals.
- for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
+ for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
RETURN_IF_EMPTY_HANDLE_VALUE(
isolate,
SetProperty(local_scope,
@@ -9958,37 +10348,40 @@
Handle<JSObject>());
}
- // Third fill all context locals.
- Handle<Context> frame_context(Context::cast(frame->context()));
- Handle<Context> function_context(frame_context->fcontext());
- if (!CopyContextLocalsToScopeObject(isolate,
- serialized_scope_info, scope_info,
- function_context, local_scope)) {
- return Handle<JSObject>();
- }
+ if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
+ // Third fill all context locals.
+ Handle<Context> frame_context(Context::cast(frame->context()));
+ Handle<Context> function_context(frame_context->declaration_context());
+ if (!CopyContextLocalsToScopeObject(isolate,
+ serialized_scope_info, scope_info,
+ function_context, local_scope)) {
+ return Handle<JSObject>();
+ }
- // Finally copy any properties from the function context extension. This will
- // be variables introduced by eval.
- if (function_context->closure() == *function) {
- if (function_context->has_extension() &&
- !function_context->IsGlobalContext()) {
- Handle<JSObject> ext(JSObject::cast(function_context->extension()));
- Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
- for (int i = 0; i < keys->length(); i++) {
- // Names of variables introduced by eval are strings.
- ASSERT(keys->get(i)->IsString());
- Handle<String> key(String::cast(keys->get(i)));
- RETURN_IF_EMPTY_HANDLE_VALUE(
- isolate,
- SetProperty(local_scope,
- key,
- GetProperty(ext, key),
- NONE,
- kNonStrictMode),
- Handle<JSObject>());
+ // Finally copy any properties from the function context extension.
+ // These will be variables introduced by eval.
+ if (function_context->closure() == *function) {
+ if (function_context->has_extension() &&
+ !function_context->IsGlobalContext()) {
+ Handle<JSObject> ext(JSObject::cast(function_context->extension()));
+ Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
+ for (int i = 0; i < keys->length(); i++) {
+ // Names of variables introduced by eval are strings.
+ ASSERT(keys->get(i)->IsString());
+ Handle<String> key(String::cast(keys->get(i)));
+ RETURN_IF_EMPTY_HANDLE_VALUE(
+ isolate,
+ SetProperty(local_scope,
+ key,
+ GetProperty(ext, key),
+ NONE,
+ kNonStrictMode),
+ Handle<JSObject>());
+ }
}
}
}
+
return local_scope;
}
@@ -9997,7 +10390,7 @@
// context.
static Handle<JSObject> MaterializeClosure(Isolate* isolate,
Handle<Context> context) {
- ASSERT(context->is_function_context());
+ ASSERT(context->IsFunctionContext());
Handle<SharedFunctionInfo> shared(context->closure()->shared());
Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
@@ -10008,29 +10401,6 @@
Handle<JSObject> closure_scope =
isolate->factory()->NewJSObject(isolate->object_function());
- // Check whether the arguments shadow object exists.
- int arguments_shadow_index =
- shared->scope_info()->ContextSlotIndex(
- isolate->heap()->arguments_shadow_symbol(), NULL);
- if (arguments_shadow_index >= 0) {
- // In this case all the arguments are available in the arguments shadow
- // object.
- Handle<JSObject> arguments_shadow(
- JSObject::cast(context->get(arguments_shadow_index)));
- for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
- // We don't expect exception-throwing getters on the arguments shadow.
- Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
- RETURN_IF_EMPTY_HANDLE_VALUE(
- isolate,
- SetProperty(closure_scope,
- scope_info.parameter_name(i),
- Handle<Object>(element, isolate),
- NONE,
- kNonStrictMode),
- Handle<JSObject>());
- }
- }
-
// Fill all context locals to the context extension.
if (!CopyContextLocalsToScopeObject(isolate,
serialized_scope_info, scope_info,
@@ -10062,6 +10432,23 @@
}
+// Create a plain JSObject which materializes the scope for the specified
+// catch context.
+static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
+ Handle<Context> context) {
+ ASSERT(context->IsCatchContext());
+ Handle<String> name(String::cast(context->extension()));
+ Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
+ Handle<JSObject> catch_scope =
+ isolate->factory()->NewJSObject(isolate->object_function());
+ RETURN_IF_EMPTY_HANDLE_VALUE(
+ isolate,
+ SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
+ Handle<JSObject>());
+ return catch_scope;
+}
+
+
// Iterate over the actual scopes visible from a stack frame. All scopes are
// backed by an actual context except the local scope, which is inserted
// "artifically" in the context chain.
@@ -10072,10 +10459,6 @@
ScopeTypeLocal,
ScopeTypeWith,
ScopeTypeClosure,
- // Every catch block contains an implicit with block (its parameter is
- // a JSContextExtensionObject) that extends current scope with a variable
- // holding exception object. Such with blocks are treated as scopes of their
- // own type.
ScopeTypeCatch
};
@@ -10096,11 +10479,11 @@
int index = function_->shared()->scope_info()->
StackSlotIndex(isolate_->heap()->result_symbol());
at_local_ = index < 0;
- } else if (context_->is_function_context()) {
+ } else if (context_->IsFunctionContext()) {
at_local_ = true;
} else if (context_->closure() != *function_) {
- // The context_ is a with block from the outer function.
- ASSERT(context_->has_extension());
+ // The context_ is a with or catch block from the outer function.
+ ASSERT(context_->IsWithContext() || context_->IsCatchContext());
at_local_ = true;
}
}
@@ -10130,16 +10513,12 @@
}
// Move to the next context.
- if (context_->is_function_context()) {
- context_ = Handle<Context>(Context::cast(context_->closure()->context()));
- } else {
- context_ = Handle<Context>(context_->previous());
- }
+ context_ = Handle<Context>(context_->previous(), isolate_);
// If passing the local scope indicate that the current scope is now the
// local scope.
if (!local_done_ &&
- (context_->IsGlobalContext() || (context_->is_function_context()))) {
+ (context_->IsGlobalContext() || context_->IsFunctionContext())) {
at_local_ = true;
}
}
@@ -10153,18 +10532,13 @@
ASSERT(context_->global()->IsGlobalObject());
return ScopeTypeGlobal;
}
- if (context_->is_function_context()) {
+ if (context_->IsFunctionContext()) {
return ScopeTypeClosure;
}
- ASSERT(context_->has_extension());
- // Current scope is either an explicit with statement or a with statement
- // implicitely generated for a catch block.
- // If the extension object here is a JSContextExtensionObject then
- // current with statement is one frome a catch block otherwise it's a
- // regular with statement.
- if (context_->extension()->IsJSContextExtensionObject()) {
+ if (context_->IsCatchContext()) {
return ScopeTypeCatch;
}
+ ASSERT(context_->IsWithContext());
return ScopeTypeWith;
}
@@ -10173,20 +10547,17 @@
switch (Type()) {
case ScopeIterator::ScopeTypeGlobal:
return Handle<JSObject>(CurrentContext()->global());
- break;
case ScopeIterator::ScopeTypeLocal:
// Materialize the content of the local scope into a JSObject.
return MaterializeLocalScope(isolate_, frame_);
- break;
case ScopeIterator::ScopeTypeWith:
+ // Return the with object.
+ return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
case ScopeIterator::ScopeTypeCatch:
- // Return the with object.
- return Handle<JSObject>(CurrentContext()->extension());
- break;
+ return MaterializeCatchScope(isolate_, CurrentContext());
case ScopeIterator::ScopeTypeClosure:
// Materialize the content of the closure scope into a JSObject.
return MaterializeClosure(isolate_, CurrentContext());
- break;
}
UNREACHABLE();
return Handle<JSObject>();
@@ -10217,8 +10588,7 @@
if (!CurrentContext().is_null()) {
CurrentContext()->Print();
if (CurrentContext()->has_extension()) {
- Handle<JSObject> extension =
- Handle<JSObject>(CurrentContext()->extension());
+ Handle<Object> extension(CurrentContext()->extension());
if (extension->IsJSContextExtensionObject()) {
extension->Print();
}
@@ -10227,34 +10597,27 @@
break;
}
- case ScopeIterator::ScopeTypeWith: {
+ case ScopeIterator::ScopeTypeWith:
PrintF("With:\n");
- Handle<JSObject> extension =
- Handle<JSObject>(CurrentContext()->extension());
- extension->Print();
+ CurrentContext()->extension()->Print();
break;
- }
- case ScopeIterator::ScopeTypeCatch: {
+ case ScopeIterator::ScopeTypeCatch:
PrintF("Catch:\n");
- Handle<JSObject> extension =
- Handle<JSObject>(CurrentContext()->extension());
- extension->Print();
+ CurrentContext()->extension()->Print();
+ CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
break;
- }
- case ScopeIterator::ScopeTypeClosure: {
+ case ScopeIterator::ScopeTypeClosure:
PrintF("Closure:\n");
CurrentContext()->Print();
if (CurrentContext()->has_extension()) {
- Handle<JSObject> extension =
- Handle<JSObject>(CurrentContext()->extension());
+ Handle<Object> extension(CurrentContext()->extension());
if (extension->IsJSContextExtensionObject()) {
extension->Print();
}
}
break;
- }
default:
UNREACHABLE();
@@ -10725,19 +11088,35 @@
// Creates a copy of the with context chain. The copy of the context chain is
// is linked to the function context supplied.
-static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
- Handle<Context> function_context) {
- // At the bottom of the chain. Return the function context to link to.
- if (context_chain->is_function_context()) {
- return function_context;
+static Handle<Context> CopyWithContextChain(Isolate* isolate,
+ Handle<JSFunction> function,
+ Handle<Context> current,
+ Handle<Context> base) {
+ // At the end of the chain. Return the base context to link to.
+ if (current->IsFunctionContext() || current->IsGlobalContext()) {
+ return base;
}
- // Recursively copy the with contexts.
- Handle<Context> previous(context_chain->previous());
- Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
- Handle<Context> context = CopyWithContextChain(previous, function_context);
- return context->GetIsolate()->factory()->NewWithContext(
- context, extension, context_chain->IsCatchContext());
+ // Recursively copy the with and catch contexts.
+ HandleScope scope(isolate);
+ Handle<Context> previous(current->previous());
+ Handle<Context> new_previous =
+ CopyWithContextChain(isolate, function, previous, base);
+ Handle<Context> new_current;
+ if (current->IsCatchContext()) {
+ Handle<String> name(String::cast(current->extension()));
+ Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
+ new_current =
+ isolate->factory()->NewCatchContext(function,
+ new_previous,
+ name,
+ thrown_object);
+ } else {
+ Handle<JSObject> extension(JSObject::cast(current->extension()));
+ new_current =
+ isolate->factory()->NewWithContext(function, new_previous, extension);
+ }
+ return scope.CloseAndEscape(new_current);
}
@@ -10865,12 +11244,13 @@
context->set_extension(*local_scope);
// Copy any with contexts present and chain them in front of this context.
Handle<Context> frame_context(Context::cast(frame->context()));
- Handle<Context> function_context(frame_context->fcontext());
- context = CopyWithContextChain(frame_context, context);
+ Handle<Context> function_context(frame_context->declaration_context());
+ context = CopyWithContextChain(isolate, go_between, frame_context, context);
if (additional_context->IsJSObject()) {
- context = isolate->factory()->NewWithContext(context,
- Handle<JSObject>::cast(additional_context), false);
+ Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
+ context =
+ isolate->factory()->NewWithContext(go_between, context, extension);
}
// Wrap the evaluation statement in a new function compiled in the newly
@@ -11627,7 +12007,7 @@
// Deletes the specified live object list.
RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
#ifdef LIVE_OBJECT_LIST
- CONVERT_SMI_CHECKED(id, args[0]);
+ CONVERT_SMI_ARG_CHECKED(id, 0);
bool success = LiveObjectList::Delete(id);
return success ? isolate->heap()->true_value() :
isolate->heap()->false_value();
@@ -11645,10 +12025,10 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
#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_SMI_ARG_CHECKED(id1, 0);
+ CONVERT_SMI_ARG_CHECKED(id2, 1);
+ CONVERT_SMI_ARG_CHECKED(start, 2);
+ CONVERT_SMI_ARG_CHECKED(count, 3);
CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
EnterDebugger enter_debugger;
return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
@@ -11662,7 +12042,7 @@
// This is only used for obj ids shown in live object lists.
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
#ifdef LIVE_OBJECT_LIST
- CONVERT_SMI_CHECKED(obj_id, args[0]);
+ CONVERT_SMI_ARG_CHECKED(obj_id, 0);
Object* result = LiveObjectList::GetObj(obj_id);
return result;
#else
@@ -11689,7 +12069,7 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
#ifdef LIVE_OBJECT_LIST
HandleScope scope;
- CONVERT_SMI_CHECKED(obj_id, args[0]);
+ CONVERT_SMI_ARG_CHECKED(obj_id, 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());
@@ -11706,11 +12086,11 @@
}
int start = 0;
if (args[3]->IsSmi()) {
- start = Smi::cast(args[3])->value();
+ start = args.smi_at(3);
}
int limit = Smi::kMaxValue;
if (args[4]->IsSmi()) {
- limit = Smi::cast(args[4])->value();
+ limit = args.smi_at(4);
}
return LiveObjectList::GetObjRetainers(obj_id,
@@ -11729,8 +12109,8 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
#ifdef LIVE_OBJECT_LIST
HandleScope scope;
- CONVERT_SMI_CHECKED(obj_id1, args[0]);
- CONVERT_SMI_CHECKED(obj_id2, args[1]);
+ CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
+ CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
Handle<JSObject> instance_filter;
@@ -11751,8 +12131,8 @@
// previously captured live object lists.
RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
#ifdef LIVE_OBJECT_LIST
- CONVERT_SMI_CHECKED(start, args[0]);
- CONVERT_SMI_CHECKED(count, args[1]);
+ CONVERT_SMI_ARG_CHECKED(start, 0);
+ CONVERT_SMI_ARG_CHECKED(count, 1);
return LiveObjectList::Info(start, count);
#else
return isolate->heap()->undefined_value();
@@ -11765,7 +12145,7 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
#ifdef LIVE_OBJECT_LIST
HandleScope scope;
- CONVERT_SMI_CHECKED(obj_id, args[0]);
+ CONVERT_SMI_ARG_CHECKED(obj_id, 0);
Object* result = LiveObjectList::PrintObj(obj_id);
return result;
#else
@@ -11793,8 +12173,8 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
#ifdef LIVE_OBJECT_LIST
HandleScope scope;
- CONVERT_SMI_CHECKED(id1, args[0]);
- CONVERT_SMI_CHECKED(id2, args[1]);
+ CONVERT_SMI_ARG_CHECKED(id1, 0);
+ CONVERT_SMI_ARG_CHECKED(id2, 1);
CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
EnterDebugger enter_debugger;
@@ -11810,22 +12190,14 @@
#ifdef ENABLE_LOGGING_AND_PROFILING
RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
NoHandleAllocation ha;
- ASSERT(args.length() == 2);
-
- CONVERT_CHECKED(Smi, smi_modules, args[0]);
- CONVERT_CHECKED(Smi, smi_tag, args[1]);
- v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
+ v8::V8::ResumeProfiler();
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
NoHandleAllocation ha;
- ASSERT(args.length() == 2);
-
- CONVERT_CHECKED(Smi, smi_modules, args[0]);
- CONVERT_CHECKED(Smi, smi_tag, args[1]);
- v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
+ v8::V8::PauseProfiler();
return isolate->heap()->undefined_value();
}
@@ -11985,8 +12357,8 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
ASSERT(args.length() == 2);
- OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
- Smi::cast(args[1])->value());
+ OS::PrintError("abort: %s\n",
+ reinterpret_cast<char*>(args[0]) + args.smi_at(1));
isolate->PrintStack();
OS::Abort();
UNREACHABLE();
@@ -12188,6 +12560,28 @@
}
+#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
+ RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
+ CONVERT_CHECKED(JSObject, obj, args[0]); \
+ return isolate->heap()->ToBoolean(obj->Has##Name()); \
+ }
+
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
+
+#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
+
// ----------------------------------------------------------------------------
// Implementation of Runtime
Property changes on: src/runtime.cc
___________________________________________________________________
Modified: svn:mergeinfo
Merged /branches/bleeding_edge/src/runtime.cc:r8062-8597
« no previous file with comments | « src/runtime.h ('k') | src/runtime-profiler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698