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

Unified Diff: src/builtins.cc

Issue 1321773002: Adding ElementsAccessor::Slice (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@2015-08-10_array_builtin_splice
Patch Set: Imprving ClampedToInteger readability Created 5 years, 4 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 | « no previous file | src/elements.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/builtins.cc
diff --git a/src/builtins.cc b/src/builtins.cc
index 021615217c42a3935c9b1ed5a6d2bf6b3e34e311..c4ed125a01573a2110febcd279bbbd060e056b8c 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -134,7 +134,7 @@ BUILTIN_LIST_C(DEF_ARG_TYPE)
#ifdef DEBUG
-static inline bool CalledAsConstructor(Isolate* isolate) {
+inline bool CalledAsConstructor(Isolate* isolate) {
// Calculate the result using a full stack frame iterator and check
// that the state of the stack is as we assume it to be in the
// code below.
@@ -165,16 +165,25 @@ static inline bool CalledAsConstructor(Isolate* isolate) {
// ----------------------------------------------------------------------------
-bool ClampedToInteger(Object* object, int* out) {
+inline bool ClampedToInteger(Object* object, int* out) {
// This is an extended version of ECMA-262 7.1.11 handling signed values
// Try to convert object to a number and clamp values to [kMinInt, kMaxInt]
if (object->IsSmi()) {
*out = Smi::cast(object)->value();
return true;
} else if (object->IsHeapNumber()) {
- *out = FastD2IChecked(HeapNumber::cast(object)->value());
+ double value = HeapNumber::cast(object)->value();
+ if (std::isnan(value)) {
+ *out = 0;
+ } else if (value > kMaxInt) {
+ *out = kMaxInt;
+ } else if (value < kMinInt) {
+ *out = kMinInt;
+ } else {
+ *out = static_cast<int>(value);
+ }
return true;
- } else if (object->IsUndefined()) {
+ } else if (object->IsUndefined() || object->IsNull()) {
*out = 0;
return true;
} else if (object->IsBoolean()) {
@@ -185,15 +194,31 @@ bool ClampedToInteger(Object* object, int* out) {
}
-static void MoveDoubleElements(FixedDoubleArray* dst, int dst_index,
- FixedDoubleArray* src, int src_index, int len) {
+void MoveDoubleElements(FixedDoubleArray* dst, int dst_index,
+ FixedDoubleArray* src, int src_index, int len) {
if (len == 0) return;
MemMove(dst->data_start() + dst_index, src->data_start() + src_index,
len * kDoubleSize);
}
-static bool ArrayPrototypeHasNoElements(PrototypeIterator* iter) {
+inline bool GetSloppyArgumentsLength(Isolate* isolate, Handle<JSObject> object,
+ int* out) {
+ Map* arguments_map =
+ isolate->context()->native_context()->sloppy_arguments_map();
+ if (object->map() != arguments_map || !object->HasFastElements()) {
+ return false;
+ }
+ Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
+ if (!len_obj->IsSmi()) {
+ return false;
+ }
+ *out = Smi::cast(len_obj)->value();
+ return *out <= object->elements()->length();
+}
+
+
+bool PrototypeHasNoElements(PrototypeIterator* iter) {
DisallowHeapAllocation no_gc;
for (; !iter->IsAtEnd(); iter->Advance()) {
if (iter->GetCurrent()->IsJSProxy()) return false;
@@ -206,8 +231,8 @@ static bool ArrayPrototypeHasNoElements(PrototypeIterator* iter) {
}
-static inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate,
- JSArray* receiver) {
+inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate,
+ JSArray* receiver) {
DisallowHeapAllocation no_gc;
// If the array prototype chain is intact (and free of elements), and if the
// receiver's prototype is the array prototype, then we are done.
@@ -220,16 +245,14 @@ static inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate,
// Slow case.
PrototypeIterator iter(isolate, receiver);
- return ArrayPrototypeHasNoElements(&iter);
+ return PrototypeHasNoElements(&iter);
}
// Returns empty handle if not applicable.
MUST_USE_RESULT
-static inline MaybeHandle<FixedArrayBase> EnsureJSArrayWithWritableFastElements(
- Isolate* isolate,
- Handle<Object> receiver,
- Arguments* args,
+inline MaybeHandle<FixedArrayBase> EnsureJSArrayWithWritableFastElements(
+ Isolate* isolate, Handle<Object> receiver, Arguments* args,
int first_added_arg) {
if (!receiver->IsJSArray()) return MaybeHandle<FixedArrayBase>();
Handle<JSArray> array = Handle<JSArray>::cast(receiver);
@@ -495,140 +518,79 @@ BUILTIN(ArrayUnshift) {
BUILTIN(ArraySlice) {
HandleScope scope(isolate);
Handle<Object> receiver = args.receiver();
+ Handle<JSObject> object;
+ Handle<FixedArrayBase> elms_obj;
int len = -1;
int relative_start = 0;
int relative_end = 0;
- {
- DisallowHeapAllocation no_gc;
- if (receiver->IsJSArray()) {
- JSArray* array = JSArray::cast(*receiver);
- if (!IsJSArrayFastElementMovingAllowed(isolate, array)) {
- AllowHeapAllocation allow_allocation;
- return CallJsIntrinsic(isolate, isolate->array_slice(), args);
- }
-
- if (!array->HasFastElements()) {
- AllowHeapAllocation allow_allocation;
- return CallJsIntrinsic(isolate, isolate->array_slice(), args);
- }
+ bool is_sloppy_arguments = false;
- len = Smi::cast(array->length())->value();
- } else {
- // Array.slice(arguments, ...) is quite a common idiom (notably more
- // than 50% of invocations in Web apps). Treat it in C++ as well.
- Map* arguments_map =
- isolate->context()->native_context()->sloppy_arguments_map();
-
- bool is_arguments_object_with_fast_elements =
- receiver->IsJSObject() &&
- JSObject::cast(*receiver)->map() == arguments_map;
- if (!is_arguments_object_with_fast_elements) {
- AllowHeapAllocation allow_allocation;
- return CallJsIntrinsic(isolate, isolate->array_slice(), args);
- }
- JSObject* object = JSObject::cast(*receiver);
-
- if (!object->HasFastElements()) {
- AllowHeapAllocation allow_allocation;
- return CallJsIntrinsic(isolate, isolate->array_slice(), args);
- }
-
- Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
- if (!len_obj->IsSmi()) {
- AllowHeapAllocation allow_allocation;
- return CallJsIntrinsic(isolate, isolate->array_slice(), args);
- }
- len = Smi::cast(len_obj)->value();
- if (len > object->elements()->length()) {
- AllowHeapAllocation allow_allocation;
- return CallJsIntrinsic(isolate, isolate->array_slice(), args);
- }
+ if (receiver->IsJSArray()) {
+ DisallowHeapAllocation no_gc;
+ JSArray* array = JSArray::cast(*receiver);
+ if (!array->HasFastElements() ||
+ !IsJSArrayFastElementMovingAllowed(isolate, array)) {
+ AllowHeapAllocation allow_allocation;
+ return CallJsIntrinsic(isolate, isolate->array_slice(), args);
}
-
- DCHECK(len >= 0);
- int n_arguments = args.length() - 1;
-
- // Note carefully choosen defaults---if argument is missing,
- // it's undefined which gets converted to 0 for relative_start
- // and to len for relative_end.
- relative_start = 0;
- relative_end = len;
- if (n_arguments > 0) {
- Object* arg1 = args[1];
- if (arg1->IsSmi()) {
- relative_start = Smi::cast(arg1)->value();
- } else if (arg1->IsHeapNumber()) {
- double start = HeapNumber::cast(arg1)->value();
- if (start < kMinInt || start > kMaxInt) {
- AllowHeapAllocation allow_allocation;
- return CallJsIntrinsic(isolate, isolate->array_slice(), args);
- }
- relative_start = std::isnan(start) ? 0 : static_cast<int>(start);
- } else if (!arg1->IsUndefined()) {
+ len = Smi::cast(array->length())->value();
+ object = Handle<JSObject>::cast(receiver);
+ elms_obj = handle(array->elements(), isolate);
+ } else if (receiver->IsJSObject() &&
+ GetSloppyArgumentsLength(isolate, Handle<JSObject>::cast(receiver),
+ &len)) {
+ // Array.prototype.slice(arguments, ...) is quite a common idiom
+ // (notably more than 50% of invocations in Web apps).
+ // Treat it in C++ as well.
+ is_sloppy_arguments = true;
+ object = Handle<JSObject>::cast(receiver);
+ elms_obj = handle(object->elements(), isolate);
+ } else {
+ AllowHeapAllocation allow_allocation;
+ return CallJsIntrinsic(isolate, isolate->array_slice(), args);
+ }
+ DCHECK(len >= 0);
+ int argument_count = args.length() - 1;
+ // Note carefully chosen defaults---if argument is missing,
+ // it's undefined which gets converted to 0 for relative_start
+ // and to len for relative_end.
+ relative_start = 0;
+ relative_end = len;
+ if (argument_count > 0) {
+ DisallowHeapAllocation no_gc;
+ if (!ClampedToInteger(args[1], &relative_start)) {
+ AllowHeapAllocation allow_allocation;
+ return CallJsIntrinsic(isolate, isolate->array_slice(), args);
+ }
+ if (argument_count > 1) {
+ Object* end_arg = args[2];
+ // slice handles the end_arg specially
+ if (end_arg->IsUndefined()) {
+ relative_end = len;
+ } else if (!ClampedToInteger(end_arg, &relative_end)) {
AllowHeapAllocation allow_allocation;
return CallJsIntrinsic(isolate, isolate->array_slice(), args);
}
- if (n_arguments > 1) {
- Object* arg2 = args[2];
- if (arg2->IsSmi()) {
- relative_end = Smi::cast(arg2)->value();
- } else if (arg2->IsHeapNumber()) {
- double end = HeapNumber::cast(arg2)->value();
- if (end < kMinInt || end > kMaxInt) {
- AllowHeapAllocation allow_allocation;
- return CallJsIntrinsic(isolate, isolate->array_slice(), args);
- }
- relative_end = std::isnan(end) ? 0 : static_cast<int>(end);
- } else if (!arg2->IsUndefined()) {
- AllowHeapAllocation allow_allocation;
- return CallJsIntrinsic(isolate, isolate->array_slice(), args);
- }
- }
}
}
// ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
- int k = (relative_start < 0) ? Max(len + relative_start, 0)
- : Min(relative_start, len);
+ uint32_t actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
+ : Min(relative_start, len);
// ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
- int final = (relative_end < 0) ? Max(len + relative_end, 0)
- : Min(relative_end, len);
-
- // Calculate the length of result array.
- int result_len = Max(final - k, 0);
+ uint32_t actual_end =
+ (relative_end < 0) ? Max(len + relative_end, 0) : Min(relative_end, len);
- Handle<JSObject> object = Handle<JSObject>::cast(receiver);
- Handle<FixedArrayBase> elms(object->elements(), isolate);
-
- ElementsKind kind = object->GetElementsKind();
- if (IsHoleyElementsKind(kind)) {
- DisallowHeapAllocation no_gc;
- bool packed = true;
- ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
- for (int i = k; i < final; i++) {
- if (!accessor->HasElement(object, i, elms)) {
- packed = false;
- break;
- }
- }
- if (packed) {
- kind = GetPackedElementsKind(kind);
- } else if (!receiver->IsJSArray()) {
- AllowHeapAllocation allow_allocation;
- return CallJsIntrinsic(isolate, isolate->array_slice(), args);
- }
+ ElementsAccessor* accessor = object->GetElementsAccessor();
+ if (is_sloppy_arguments &&
+ !accessor->IsPacked(object, elms_obj, actual_start, actual_end)) {
+ // Don't deal with arguments with holes in C++
+ AllowHeapAllocation allow_allocation;
+ return CallJsIntrinsic(isolate, isolate->array_slice(), args);
}
-
Handle<JSArray> result_array =
- isolate->factory()->NewJSArray(kind, result_len, result_len);
-
- DisallowHeapAllocation no_gc;
- if (result_len == 0) return *result_array;
-
- ElementsAccessor* accessor = object->GetElementsAccessor();
- accessor->CopyElements(
- elms, k, kind, handle(result_array->elements(), isolate), 0, result_len);
+ accessor->Slice(object, elms_obj, actual_start, actual_end);
return *result_array;
}
@@ -687,9 +649,9 @@ BUILTIN(ArraySplice) {
return CallJsIntrinsic(isolate, isolate->array_splice(), args);
}
ElementsAccessor* accessor = array->GetElementsAccessor();
- Handle<JSArray> result = accessor->Splice(
+ Handle<JSArray> result_array = accessor->Splice(
array, elms_obj, actual_start, actual_delete_count, args, add_count);
- return *result;
+ return *result_array;
}
@@ -706,7 +668,7 @@ BUILTIN(ArrayConcat) {
Object* array_proto = native_context->array_function()->prototype();
PrototypeIterator iter(isolate, array_proto,
PrototypeIterator::START_AT_RECEIVER);
- if (!ArrayPrototypeHasNoElements(&iter)) {
+ if (!PrototypeHasNoElements(&iter)) {
AllowHeapAllocation allow_allocation;
return CallJsIntrinsic(isolate, isolate->array_concat(), args);
}
« no previous file with comments | « no previous file | src/elements.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698