New version of v8 from bleeding edge at revision 3649
diff --git a/src/runtime.cc b/src/runtime.cc
index b07361a..b6da528 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -398,6 +398,82 @@
}
+static Object* Runtime_CreateObjectLiteral(Arguments args) {
+ HandleScope scope;
+ ASSERT(args.length() == 3);
+ CONVERT_ARG_CHECKED(FixedArray, literals, 0);
+ CONVERT_SMI_CHECKED(literals_index, args[1]);
+ CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
+
+ // Check if boilerplate exists. If not, create it first.
+ Handle<Object> boilerplate(literals->get(literals_index));
+ if (*boilerplate == Heap::undefined_value()) {
+ boilerplate = CreateObjectLiteralBoilerplate(literals, constant_properties);
+ if (boilerplate.is_null()) return Failure::Exception();
+ // Update the functions literal and return the boilerplate.
+ literals->set(literals_index, *boilerplate);
+ }
+ return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
+}
+
+
+static Object* Runtime_CreateObjectLiteralShallow(Arguments args) {
+ HandleScope scope;
+ ASSERT(args.length() == 3);
+ CONVERT_ARG_CHECKED(FixedArray, literals, 0);
+ CONVERT_SMI_CHECKED(literals_index, args[1]);
+ CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
+
+ // Check if boilerplate exists. If not, create it first.
+ Handle<Object> boilerplate(literals->get(literals_index));
+ if (*boilerplate == Heap::undefined_value()) {
+ boilerplate = CreateObjectLiteralBoilerplate(literals, constant_properties);
+ if (boilerplate.is_null()) return Failure::Exception();
+ // Update the functions literal and return the boilerplate.
+ literals->set(literals_index, *boilerplate);
+ }
+ return Heap::CopyJSObject(JSObject::cast(*boilerplate));
+}
+
+
+static Object* Runtime_CreateArrayLiteral(Arguments args) {
+ HandleScope scope;
+ ASSERT(args.length() == 3);
+ CONVERT_ARG_CHECKED(FixedArray, literals, 0);
+ CONVERT_SMI_CHECKED(literals_index, args[1]);
+ CONVERT_ARG_CHECKED(FixedArray, elements, 2);
+
+ // Check if boilerplate exists. If not, create it first.
+ Handle<Object> boilerplate(literals->get(literals_index));
+ if (*boilerplate == Heap::undefined_value()) {
+ boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
+ if (boilerplate.is_null()) return Failure::Exception();
+ // Update the functions literal and return the boilerplate.
+ literals->set(literals_index, *boilerplate);
+ }
+ return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
+}
+
+
+static Object* Runtime_CreateArrayLiteralShallow(Arguments args) {
+ HandleScope scope;
+ ASSERT(args.length() == 3);
+ CONVERT_ARG_CHECKED(FixedArray, literals, 0);
+ CONVERT_SMI_CHECKED(literals_index, args[1]);
+ CONVERT_ARG_CHECKED(FixedArray, elements, 2);
+
+ // Check if boilerplate exists. If not, create it first.
+ Handle<Object> boilerplate(literals->get(literals_index));
+ if (*boilerplate == Heap::undefined_value()) {
+ boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
+ if (boilerplate.is_null()) return Failure::Exception();
+ // Update the functions literal and return the boilerplate.
+ literals->set(literals_index, *boilerplate);
+ }
+ return Heap::CopyJSObject(JSObject::cast(*boilerplate));
+}
+
+
static Object* Runtime_CreateCatchExtensionObject(Arguments args) {
ASSERT(args.length() == 2);
CONVERT_CHECKED(String, key, args[0]);
@@ -483,6 +559,82 @@
}
+// Recursively traverses hidden prototypes if property is not found
+static void GetOwnPropertyImplementation(JSObject* obj,
+ String* name,
+ LookupResult* result) {
+ obj->LocalLookupRealNamedProperty(name, result);
+
+ if (!result->IsProperty()) {
+ Object* proto = obj->GetPrototype();
+ if (proto->IsJSObject() &&
+ JSObject::cast(proto)->map()->is_hidden_prototype())
+ GetOwnPropertyImplementation(JSObject::cast(proto),
+ name, result);
+ }
+}
+
+
+// Returns an array with the property description:
+// if args[1] is not a property on args[0]
+// returns undefined
+// if args[1] is a data property on args[0]
+// [false, value, Writeable, Enumerable, Configurable]
+// if args[1] is an accessor on args[0]
+// [true, GetFunction, SetFunction, Enumerable, Configurable]
+static Object* Runtime_GetOwnProperty(Arguments args) {
+ ASSERT(args.length() == 2);
+ HandleScope scope;
+ Handle<FixedArray> elms = Factory::NewFixedArray(5);
+ Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
+ LookupResult result;
+ CONVERT_CHECKED(JSObject, obj, args[0]);
+ CONVERT_CHECKED(String, name, args[1]);
+
+ // Use recursive implementation to also traverse hidden prototypes
+ GetOwnPropertyImplementation(obj, name, &result);
+
+ if (!result.IsProperty())
+ return Heap::undefined_value();
+
+ if (result.type() == CALLBACKS) {
+ Object* structure = result.GetCallbackObject();
+ if (structure->IsProxy()) {
+ // Property that is internally implemented as a callback.
+ Object* value = obj->GetPropertyWithCallback(
+ obj, structure, name, result.holder());
+ elms->set(0, Heap::false_value());
+ elms->set(1, value);
+ elms->set(2, Heap::ToBoolean(!result.IsReadOnly()));
+ } else if (structure->IsFixedArray()) {
+ // __defineGetter__/__defineSetter__ callback.
+ elms->set(0, Heap::true_value());
+ elms->set(1, FixedArray::cast(structure)->get(0));
+ elms->set(2, FixedArray::cast(structure)->get(1));
+ } else {
+ // TODO(ricow): Handle API callbacks.
+ return Heap::undefined_value();
+ }
+ } else {
+ elms->set(0, Heap::false_value());
+ elms->set(1, result.GetLazyValue());
+ elms->set(2, Heap::ToBoolean(!result.IsReadOnly()));
+ }
+
+ elms->set(3, Heap::ToBoolean(!result.IsDontEnum()));
+ elms->set(4, Heap::ToBoolean(!result.IsReadOnly()));
+ return *desc;
+}
+
+
+static Object* Runtime_IsExtensible(Arguments args) {
+ ASSERT(args.length() == 1);
+ CONVERT_CHECKED(JSObject, obj, args[0]);
+ return obj->map()->is_extensible() ? Heap::true_value()
+ : Heap::false_value();
+}
+
+
static Object* Runtime_RegExpCompile(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 3);
@@ -644,7 +796,7 @@
// Copy the function and update its context. Use it as value.
Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(value);
Handle<JSFunction> function =
- Factory::NewFunctionFromBoilerplate(boilerplate, context);
+ Factory::NewFunctionFromBoilerplate(boilerplate, context, TENURED);
value = function;
}
@@ -1082,6 +1234,7 @@
RUNTIME_ASSERT(last_match_info->HasFastElements());
RUNTIME_ASSERT(index >= 0);
RUNTIME_ASSERT(index <= subject->length());
+ Counters::regexp_entry_runtime.Increment();
Handle<Object> result = RegExpImpl::Exec(regexp,
subject,
index,
@@ -1308,6 +1461,17 @@
}
+static Object* CharFromCode(Object* char_code) {
+ uint32_t code;
+ if (Array::IndexFromObject(char_code, &code)) {
+ if (code <= 0xffff) {
+ return Heap::LookupSingleCharacterStringFromCode(code);
+ }
+ }
+ return Heap::empty_string();
+}
+
+
static Object* Runtime_StringCharCodeAt(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -1318,16 +1482,24 @@
}
+static Object* Runtime_StringCharAt(Arguments args) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 2);
+
+ CONVERT_CHECKED(String, subject, args[0]);
+ Object* index = args[1];
+ Object* code = CharCodeAt(subject, index);
+ if (code == Heap::nan_value()) {
+ return Heap::undefined_value();
+ }
+ return CharFromCode(code);
+}
+
+
static Object* Runtime_CharFromCode(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- uint32_t code;
- if (Array::IndexFromObject(args[0], &code)) {
- if (code <= 0xffff) {
- return Heap::LookupSingleCharacterStringFromCode(code);
- }
- }
- return Heap::empty_string();
+ return CharFromCode(args[0]);
}
// Forward declarations.
@@ -1433,7 +1605,7 @@
void IncrementCharacterCount(int by) {
- if (character_count_ > Smi::kMaxValue - by) {
+ if (character_count_ > String::kMaxLength - by) {
V8::FatalProcessOutOfMemory("String.replace result too large.");
}
character_count_ += by;
@@ -2397,6 +2569,7 @@
RUNTIME_ASSERT(end >= start);
RUNTIME_ASSERT(start >= 0);
RUNTIME_ASSERT(end <= value->length());
+ Counters::sub_string_runtime.Increment();
return value->SubString(start, end);
}
@@ -2648,7 +2821,6 @@
}
-
// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
static Object* Runtime_KeyedGetProperty(Arguments args) {
NoHandleAllocation ha;
@@ -2700,6 +2872,13 @@
// If value is the hole do the general lookup.
}
}
+ } else if (args[0]->IsString() && args[1]->IsSmi()) {
+ // Fast case for string indexing using [] with a smi index.
+ HandleScope scope;
+ Handle<String> str = args.at<String>(0);
+ int index = Smi::cast(args[1])->value();
+ Handle<Object> result = GetCharAt(str, index);
+ return *result;
}
// Fall back to GetObjectProperty.
@@ -3043,6 +3222,156 @@
}
+// Find the length of the prototype chain that is to to handled as one. If a
+// prototype object is hidden it is to be viewed as part of the the object it
+// is prototype for.
+static int LocalPrototypeChainLength(JSObject* obj) {
+ int count = 1;
+ Object* proto = obj->GetPrototype();
+ while (proto->IsJSObject() &&
+ JSObject::cast(proto)->map()->is_hidden_prototype()) {
+ count++;
+ proto = JSObject::cast(proto)->GetPrototype();
+ }
+ return count;
+}
+
+
+// Return the names of the local named properties.
+// args[0]: object
+static Object* Runtime_GetLocalPropertyNames(Arguments args) {
+ HandleScope scope;
+ ASSERT(args.length() == 1);
+ if (!args[0]->IsJSObject()) {
+ return Heap::undefined_value();
+ }
+ CONVERT_ARG_CHECKED(JSObject, obj, 0);
+
+ // Skip the global proxy as it has no properties and always delegates to the
+ // real global object.
+ if (obj->IsJSGlobalProxy()) {
+ obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
+ }
+
+ // Find the number of objects making up this.
+ int length = LocalPrototypeChainLength(*obj);
+
+ // Find the number of local properties for each of the objects.
+ int* local_property_count = NewArray<int>(length);
+ int total_property_count = 0;
+ Handle<JSObject> jsproto = obj;
+ for (int i = 0; i < length; i++) {
+ int n;
+ n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
+ local_property_count[i] = n;
+ total_property_count += n;
+ if (i < length - 1) {
+ jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
+ }
+ }
+
+ // Allocate an array with storage for all the property names.
+ Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
+
+ // Get the property names.
+ jsproto = obj;
+ int proto_with_hidden_properties = 0;
+ for (int i = 0; i < length; i++) {
+ jsproto->GetLocalPropertyNames(*names,
+ i == 0 ? 0 : local_property_count[i - 1]);
+ if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
+ proto_with_hidden_properties++;
+ }
+ if (i < length - 1) {
+ jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
+ }
+ }
+
+ // Filter out name of hidden propeties object.
+ if (proto_with_hidden_properties > 0) {
+ Handle<FixedArray> old_names = names;
+ names = Factory::NewFixedArray(
+ names->length() - proto_with_hidden_properties);
+ int dest_pos = 0;
+ for (int i = 0; i < total_property_count; i++) {
+ Object* name = old_names->get(i);
+ if (name == Heap::hidden_symbol()) {
+ continue;
+ }
+ names->set(dest_pos++, name);
+ }
+ }
+
+ DeleteArray(local_property_count);
+ return *Factory::NewJSArrayWithElements(names);
+}
+
+
+// Return the names of the local indexed properties.
+// args[0]: object
+static Object* Runtime_GetLocalElementNames(Arguments args) {
+ HandleScope scope;
+ ASSERT(args.length() == 1);
+ if (!args[0]->IsJSObject()) {
+ return Heap::undefined_value();
+ }
+ CONVERT_ARG_CHECKED(JSObject, obj, 0);
+
+ int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
+ Handle<FixedArray> names = Factory::NewFixedArray(n);
+ obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
+ return *Factory::NewJSArrayWithElements(names);
+}
+
+
+// Return information on whether an object has a named or indexed interceptor.
+// args[0]: object
+static Object* Runtime_GetInterceptorInfo(Arguments args) {
+ HandleScope scope;
+ ASSERT(args.length() == 1);
+ if (!args[0]->IsJSObject()) {
+ return Smi::FromInt(0);
+ }
+ CONVERT_ARG_CHECKED(JSObject, obj, 0);
+
+ int result = 0;
+ if (obj->HasNamedInterceptor()) result |= 2;
+ if (obj->HasIndexedInterceptor()) result |= 1;
+
+ return Smi::FromInt(result);
+}
+
+
+// Return property names from named interceptor.
+// args[0]: object
+static Object* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
+ HandleScope scope;
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(JSObject, obj, 0);
+
+ if (obj->HasNamedInterceptor()) {
+ v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
+ if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
+ }
+ return Heap::undefined_value();
+}
+
+
+// Return element names from indexed interceptor.
+// args[0]: object
+static Object* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
+ HandleScope scope;
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(JSObject, obj, 0);
+
+ if (obj->HasIndexedInterceptor()) {
+ v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
+ if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
+ }
+ return Heap::undefined_value();
+}
+
+
static Object* Runtime_LocalKeys(Arguments args) {
ASSERT_EQ(args.length(), 1);
CONVERT_CHECKED(JSObject, raw_object, args[0]);
@@ -3286,6 +3615,7 @@
escaped_length += 3;
}
// We don't allow strings that are longer than a maximal length.
+ ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
if (escaped_length > String::kMaxLength) {
Top::context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
@@ -3832,20 +4162,19 @@
static Object* Runtime_StringBuilderConcat(Arguments args) {
NoHandleAllocation ha;
- ASSERT(args.length() == 2);
+ ASSERT(args.length() == 3);
CONVERT_CHECKED(JSArray, array, args[0]);
- CONVERT_CHECKED(String, special, args[1]);
+ if (!args[1]->IsSmi()) {
+ Top::context()->mark_out_of_memory();
+ return Failure::OutOfMemoryException();
+ }
+ int array_length = Smi::cast(args[1])->value();
+ CONVERT_CHECKED(String, special, args[2]);
// This assumption is used by the slice encoding in one or two smis.
ASSERT(Smi::kMaxValue >= String::kMaxLength);
int special_length = special->length();
- Object* smi_array_length = array->length();
- if (!smi_array_length->IsSmi()) {
- Top::context()->mark_out_of_memory();
- return Failure::OutOfMemoryException();
- }
- int array_length = Smi::cast(smi_array_length)->value();
if (!array->HasFastElements()) {
return Top::Throw(Heap::illegal_argument_symbol());
}
@@ -3863,6 +4192,7 @@
bool ascii = special->IsAsciiRepresentation();
int position = 0;
+ int increment = 0;
for (int i = 0; i < array_length; i++) {
Object* elt = fixed_array->get(i);
if (elt->IsSmi()) {
@@ -3875,10 +4205,10 @@
if (pos + len > special_length) {
return Top::Throw(Heap::illegal_argument_symbol());
}
- position += len;
+ increment = len;
} else {
// Position and length encoded in two smis.
- position += (-len);
+ increment = (-len);
// Get the position and check that it is also a smi.
i++;
if (i >= array_length) {
@@ -3892,17 +4222,18 @@
} else if (elt->IsString()) {
String* element = String::cast(elt);
int element_length = element->length();
- position += element_length;
+ increment = element_length;
if (ascii && !element->IsAsciiRepresentation()) {
ascii = false;
}
} else {
return Top::Throw(Heap::illegal_argument_symbol());
}
- if (position > String::kMaxLength) {
+ if (increment > String::kMaxLength - position) {
Top::context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
+ position += increment;
}
int length = position;
@@ -4116,6 +4447,8 @@
CONVERT_CHECKED(String, x, args[0]);
CONVERT_CHECKED(String, y, args[1]);
+ Counters::string_compare_runtime.Increment();
+
// A few fast case tests before we flatten.
if (x == y) return Smi::FromInt(EQUAL);
if (y->length() == 0) {
@@ -4426,8 +4759,11 @@
CONVERT_ARG_CHECKED(Context, context, 0);
CONVERT_ARG_CHECKED(JSFunction, boilerplate, 1);
+ PretenureFlag pretenure = (context->global_context() == *context)
+ ? TENURED // Allocate global closures in old space.
+ : NOT_TENURED; // Allocate local closures in new space.
Handle<JSFunction> result =
- Factory::NewFunctionFromBoilerplate(boilerplate, context);
+ Factory::NewFunctionFromBoilerplate(boilerplate, context, pretenure);
return *result;
}
@@ -5143,56 +5479,36 @@
validate);
if (boilerplate.is_null()) return Failure::Exception();
Handle<JSFunction> fun =
- Factory::NewFunctionFromBoilerplate(boilerplate, context);
+ Factory::NewFunctionFromBoilerplate(boilerplate, context, NOT_TENURED);
return *fun;
}
-static Handle<JSFunction> GetBuiltinFunction(String* name) {
- LookupResult result;
- Top::global_context()->builtins()->LocalLookup(name, &result);
- return Handle<JSFunction>(JSFunction::cast(result.GetValue()));
-}
+static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
+ ASSERT(args.length() == 3);
+ if (!args[0]->IsJSFunction()) {
+ return MakePair(Top::ThrowIllegalOperation(), NULL);
+ }
-
-static Object* CompileDirectEval(Handle<String> source) {
- // Compute the eval context.
HandleScope scope;
+ Handle<JSFunction> callee = args.at<JSFunction>(0);
+ Handle<Object> receiver; // Will be overwritten.
+
+ // Compute the calling context.
+ Handle<Context> context = Handle<Context>(Top::context());
+#ifdef DEBUG
+ // Make sure Top::context() agrees with the old code that traversed
+ // the stack frames to compute the context.
StackFrameLocator locator;
JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
- Handle<Context> context(Context::cast(frame->context()));
- bool is_global = context->IsGlobalContext();
-
- // Compile source string in the current context.
- Handle<JSFunction> boilerplate = Compiler::CompileEval(
- source,
- context,
- is_global,
- Compiler::DONT_VALIDATE_JSON);
- if (boilerplate.is_null()) return Failure::Exception();
- Handle<JSFunction> fun =
- Factory::NewFunctionFromBoilerplate(boilerplate, context);
- return *fun;
-}
-
-
-static Object* Runtime_ResolvePossiblyDirectEval(Arguments args) {
- ASSERT(args.length() == 2);
-
- HandleScope scope;
-
- CONVERT_ARG_CHECKED(JSFunction, callee, 0);
-
- Handle<Object> receiver;
+ ASSERT(Context::cast(frame->context()) == *context);
+#endif
// Find where the 'eval' symbol is bound. It is unaliased only if
// it is bound in the global context.
- StackFrameLocator locator;
- JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
- Handle<Context> context(Context::cast(frame->context()));
- int index;
- PropertyAttributes attributes;
- while (!context.is_null()) {
+ int index = -1;
+ PropertyAttributes attributes = ABSENT;
+ while (true) {
receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
&index, &attributes);
// Stop search when eval is found or when the global context is
@@ -5211,46 +5527,42 @@
Handle<Object> name = Factory::eval_symbol();
Handle<Object> reference_error =
Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
- return Top::Throw(*reference_error);
+ return MakePair(Top::Throw(*reference_error), NULL);
}
- if (context->IsGlobalContext()) {
- // 'eval' is bound in the global context, but it may have been overwritten.
- // Compare it to the builtin 'GlobalEval' function to make sure.
- Handle<JSFunction> global_eval =
- GetBuiltinFunction(Heap::global_eval_symbol());
- if (global_eval.is_identical_to(callee)) {
- // A direct eval call.
- if (args[1]->IsString()) {
- CONVERT_ARG_CHECKED(String, source, 1);
- // A normal eval call on a string. Compile it and return the
- // compiled function bound in the local context.
- Object* compiled_source = CompileDirectEval(source);
- if (compiled_source->IsFailure()) return compiled_source;
- receiver = Handle<Object>(frame->receiver());
- callee = Handle<JSFunction>(JSFunction::cast(compiled_source));
- } else {
- // An eval call that is not called on a string. Global eval
- // deals better with this.
- receiver = Handle<Object>(Top::global_context()->global());
- }
- } else {
- // 'eval' is overwritten. Just call the function with the given arguments.
- receiver = Handle<Object>(Top::global_context()->global());
- }
- } else {
+ if (!context->IsGlobalContext()) {
// 'eval' is not bound in the global context. Just call the function
// with the given arguments. This is not necessarily the global eval.
if (receiver->IsContext()) {
context = Handle<Context>::cast(receiver);
receiver = Handle<Object>(context->get(index));
+ } else if (receiver->IsJSContextExtensionObject()) {
+ receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
}
+ return MakePair(*callee, *receiver);
}
- Handle<FixedArray> call = Factory::NewFixedArray(2);
- call->set(0, *callee);
- call->set(1, *receiver);
- return *call;
+ // 'eval' is bound in the global context, but it may have been overwritten.
+ // Compare it to the builtin 'GlobalEval' function to make sure.
+ if (*callee != Top::global_context()->global_eval_fun() ||
+ !args[1]->IsString()) {
+ return MakePair(*callee, Top::context()->global()->global_receiver());
+ }
+
+ // Deal with a normal eval call with a string argument. Compile it
+ // and return the compiled function bound in the local context.
+ Handle<String> source = args.at<String>(1);
+ Handle<JSFunction> boilerplate = Compiler::CompileEval(
+ source,
+ Handle<Context>(Top::context()),
+ Top::context()->IsGlobalContext(),
+ Compiler::DONT_VALIDATE_JSON);
+ if (boilerplate.is_null()) return MakePair(Failure::Exception(), NULL);
+ callee = Factory::NewFunctionFromBoilerplate(
+ boilerplate,
+ Handle<Context>(Top::context()),
+ NOT_TENURED);
+ return MakePair(*callee, args[2]);
}
@@ -5307,11 +5619,11 @@
uint32_t index_limit,
bool fast_elements) :
storage_(storage), index_limit_(index_limit),
- fast_elements_(fast_elements), index_offset_(0) { }
+ index_offset_(0), fast_elements_(fast_elements) { }
void visit(uint32_t i, Handle<Object> elm) {
- uint32_t index = i + index_offset_;
- if (index >= index_limit_) return;
+ if (i >= index_limit_ - index_offset_) return;
+ uint32_t index = index_offset_ + i;
if (fast_elements_) {
ASSERT(index < static_cast<uint32_t>(storage_->length()));
@@ -5327,14 +5639,23 @@
}
void increase_index_offset(uint32_t delta) {
- index_offset_ += delta;
+ if (index_limit_ - index_offset_ < delta) {
+ index_offset_ = index_limit_;
+ } else {
+ index_offset_ += delta;
+ }
}
+ Handle<FixedArray> storage() { return storage_; }
+
private:
Handle<FixedArray> storage_;
+ // Limit on the accepted indices. Elements with indices larger than the
+ // limit are ignored by the visitor.
uint32_t index_limit_;
- bool fast_elements_;
+ // Index after last seen index. Always less than or equal to index_limit_.
uint32_t index_offset_;
+ bool fast_elements_;
};
@@ -5506,6 +5827,11 @@
*
* If a ArrayConcatVisitor object is given, the visitor is called with
* parameters, element's index + visitor_index_offset and the element.
+ *
+ * The returned number of elements is an upper bound on the actual number
+ * of elements added. If the same element occurs in more than one object
+ * in the array's prototype chain, it will be counted more than once, but
+ * will only occur once in the result.
*/
static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
ArrayConcatVisitor* visitor) {
@@ -5528,8 +5854,14 @@
uint32_t nof_elements = 0;
for (int i = objects.length() - 1; i >= 0; i--) {
Handle<JSObject> obj = objects[i];
- nof_elements +=
+ uint32_t encountered_elements =
IterateElements(Handle<JSObject>::cast(obj), range, visitor);
+
+ if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
+ nof_elements = JSObject::kMaxElementCount;
+ } else {
+ nof_elements += encountered_elements;
+ }
}
return nof_elements;
@@ -5546,10 +5878,12 @@
* elements. If an argument is not an Array object, the function
* visits the object as if it is an one-element array.
*
- * If the result array index overflows 32-bit integer, the rounded
+ * If the result array index overflows 32-bit unsigned integer, the rounded
* non-negative number is used as new length. For example, if one
* array length is 2^32 - 1, second array length is 1, the
* concatenated array length is 0.
+ * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
+ * is one more than the last array index to get a value assigned).
*/
static uint32_t IterateArguments(Handle<JSArray> arguments,
ArrayConcatVisitor* visitor) {
@@ -5565,16 +5899,23 @@
IterateArrayAndPrototypeElements(array, visitor);
// Total elements of array and its prototype chain can be more than
// the array length, but ArrayConcat can only concatenate at most
- // the array length number of elements.
- visited_elements += (nof_elements > len) ? len : nof_elements;
+ // the array length number of elements. We use the length as an estimate
+ // for the actual number of elements added.
+ uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
+ if (JSArray::kMaxElementCount - visited_elements < added_elements) {
+ visited_elements = JSArray::kMaxElementCount;
+ } else {
+ visited_elements += added_elements;
+ }
if (visitor) visitor->increase_index_offset(len);
-
} else {
if (visitor) {
visitor->visit(0, obj);
visitor->increase_index_offset(1);
}
- visited_elements++;
+ if (visited_elements < JSArray::kMaxElementCount) {
+ visited_elements++;
+ }
}
}
return visited_elements;
@@ -5584,6 +5925,8 @@
/**
* Array::concat implementation.
* See ECMAScript 262, 15.4.4.4.
+ * TODO(lrn): Fix non-compliance for very large concatenations and update to
+ * following the ECMAScript 5 specification.
*/
static Object* Runtime_ArrayConcat(Arguments args) {
ASSERT(args.length() == 1);
@@ -5600,12 +5943,18 @@
{ AssertNoAllocation nogc;
for (uint32_t i = 0; i < num_of_args; i++) {
Object* obj = arguments->GetElement(i);
+ uint32_t length_estimate;
if (obj->IsJSArray()) {
- result_length +=
+ length_estimate =
static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
} else {
- result_length++;
+ length_estimate = 1;
}
+ if (JSObject::kMaxElementCount - result_length < length_estimate) {
+ result_length = JSObject::kMaxElementCount;
+ break;
+ }
+ result_length += length_estimate;
}
}
@@ -5639,7 +5988,8 @@
IterateArguments(arguments, &visitor);
result->set_length(*len);
- result->set_elements(*storage);
+ // Please note the storage might have changed in the visitor.
+ result->set_elements(*visitor.storage());
return *result;
}
@@ -5814,21 +6164,6 @@
}
-// Find the length of the prototype chain that is to to handled as one. If a
-// prototype object is hidden it is to be viewed as part of the the object it
-// is prototype for.
-static int LocalPrototypeChainLength(JSObject* obj) {
- int count = 1;
- Object* proto = obj->GetPrototype();
- while (proto->IsJSObject() &&
- JSObject::cast(proto)->map()->is_hidden_prototype()) {
- count++;
- proto = JSObject::cast(proto)->GetPrototype();
- }
- return count;
-}
-
-
static Object* DebugLookupResultValue(Object* receiver, String* name,
LookupResult* result,
bool* caught_exception) {
@@ -5998,93 +6333,6 @@
}
-// Return the names of the local named properties.
-// args[0]: object
-static Object* Runtime_DebugLocalPropertyNames(Arguments args) {
- HandleScope scope;
- ASSERT(args.length() == 1);
- if (!args[0]->IsJSObject()) {
- return Heap::undefined_value();
- }
- CONVERT_ARG_CHECKED(JSObject, obj, 0);
-
- // Skip the global proxy as it has no properties and always delegates to the
- // real global object.
- if (obj->IsJSGlobalProxy()) {
- obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
- }
-
- // Find the number of objects making up this.
- int length = LocalPrototypeChainLength(*obj);
-
- // Find the number of local properties for each of the objects.
- int* local_property_count = NewArray<int>(length);
- int total_property_count = 0;
- Handle<JSObject> jsproto = obj;
- for (int i = 0; i < length; i++) {
- int n;
- n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
- local_property_count[i] = n;
- total_property_count += n;
- if (i < length - 1) {
- jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
- }
- }
-
- // Allocate an array with storage for all the property names.
- Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
-
- // Get the property names.
- jsproto = obj;
- int proto_with_hidden_properties = 0;
- for (int i = 0; i < length; i++) {
- jsproto->GetLocalPropertyNames(*names,
- i == 0 ? 0 : local_property_count[i - 1]);
- if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
- proto_with_hidden_properties++;
- }
- if (i < length - 1) {
- jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
- }
- }
-
- // Filter out name of hidden propeties object.
- if (proto_with_hidden_properties > 0) {
- Handle<FixedArray> old_names = names;
- names = Factory::NewFixedArray(
- names->length() - proto_with_hidden_properties);
- int dest_pos = 0;
- for (int i = 0; i < total_property_count; i++) {
- Object* name = old_names->get(i);
- if (name == Heap::hidden_symbol()) {
- continue;
- }
- names->set(dest_pos++, name);
- }
- }
-
- DeleteArray(local_property_count);
- return *Factory::NewJSArrayWithElements(names);
-}
-
-
-// Return the names of the local indexed properties.
-// args[0]: object
-static Object* Runtime_DebugLocalElementNames(Arguments args) {
- HandleScope scope;
- ASSERT(args.length() == 1);
- if (!args[0]->IsJSObject()) {
- return Heap::undefined_value();
- }
- CONVERT_ARG_CHECKED(JSObject, obj, 0);
-
- int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
- Handle<FixedArray> names = Factory::NewFixedArray(n);
- obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
- return *Factory::NewJSArrayWithElements(names);
-}
-
-
// Return the property type calculated from the property details.
// args[0]: smi with property details.
static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
@@ -6115,54 +6363,6 @@
}
-// Return information on whether an object has a named or indexed interceptor.
-// args[0]: object
-static Object* Runtime_DebugInterceptorInfo(Arguments args) {
- HandleScope scope;
- ASSERT(args.length() == 1);
- if (!args[0]->IsJSObject()) {
- return Smi::FromInt(0);
- }
- CONVERT_ARG_CHECKED(JSObject, obj, 0);
-
- int result = 0;
- if (obj->HasNamedInterceptor()) result |= 2;
- if (obj->HasIndexedInterceptor()) result |= 1;
-
- return Smi::FromInt(result);
-}
-
-
-// Return property names from named interceptor.
-// args[0]: object
-static Object* Runtime_DebugNamedInterceptorPropertyNames(Arguments args) {
- HandleScope scope;
- ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSObject, obj, 0);
-
- if (obj->HasNamedInterceptor()) {
- v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
- if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
- }
- return Heap::undefined_value();
-}
-
-
-// Return element names from indexed interceptor.
-// args[0]: object
-static Object* Runtime_DebugIndexedInterceptorElementNames(Arguments args) {
- HandleScope scope;
- ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSObject, obj, 0);
-
- if (obj->HasIndexedInterceptor()) {
- v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
- if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
- }
- return Heap::undefined_value();
-}
-
-
// Return property value from named interceptor.
// args[0]: object
// args[1]: property name
@@ -7808,7 +8008,8 @@
HandleScope scope;
- int initial_size = limit < 10 ? limit : 10;
+ limit = Max(limit, 0); // Ensure that limit is not negative.
+ int initial_size = Min(limit, 10);
Handle<JSArray> result = Factory::NewJSArray(initial_size * 3);
StackFrameIterator iter;