HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Nougat 7.0
|
7.0.0_r31
下载
查看原文件
收藏
根目录
external
v8
src
builtins.cc
// Copyright 2012 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/builtins.h" #include "src/api.h" #include "src/api-natives.h" #include "src/arguments.h" #include "src/base/once.h" #include "src/bootstrapper.h" #include "src/dateparser-inl.h" #include "src/elements.h" #include "src/frames-inl.h" #include "src/gdb-jit.h" #include "src/ic/handler-compiler.h" #include "src/ic/ic.h" #include "src/isolate-inl.h" #include "src/messages.h" #include "src/profiler/cpu-profiler.h" #include "src/property-descriptor.h" #include "src/prototype.h" #include "src/string-builder.h" #include "src/vm-state-inl.h" namespace v8 { namespace internal { namespace { // Arguments object passed to C++ builtins. template
class BuiltinArguments : public Arguments { public: BuiltinArguments(int length, Object** arguments) : Arguments(length, arguments) { // Check we have at least the receiver. DCHECK_LE(1, this->length()); } Object*& operator[] (int index) { DCHECK(index < length()); return Arguments::operator[](index); } template
Handle
at(int index) { DCHECK(index < length()); return Arguments::at
(index); } Handle
atOrUndefined(Isolate* isolate, int index) { if (index >= length()) { return isolate->factory()->undefined_value(); } return at
(index); } Handle
receiver() { return Arguments::at
(0); } Handle
target(); Handle
new_target(); // Gets the total number of arguments including the receiver (but // excluding extra arguments). int length() const; }; // Specialize BuiltinArguments for the extra arguments. template <> int BuiltinArguments
::length() const { return Arguments::length(); } template <> int BuiltinArguments
::length() const { return Arguments::length() - 1; } template <> Handle
BuiltinArguments
::target() { return Arguments::at
(Arguments::length() - 1); } template <> int BuiltinArguments
::length() const { return Arguments::length() - 1; } template <> Handle
BuiltinArguments
::new_target() { return Arguments::at
(Arguments::length() - 1); } template <> int BuiltinArguments
::length() const { return Arguments::length() - 2; } template <> Handle
BuiltinArguments
::target() { return Arguments::at
(Arguments::length() - 2); } template <> Handle
BuiltinArguments
::new_target() { return Arguments::at
(Arguments::length() - 1); } #define DEF_ARG_TYPE(name, spec) \ typedef BuiltinArguments
name##ArgumentsType; BUILTIN_LIST_C(DEF_ARG_TYPE) #undef DEF_ARG_TYPE // ---------------------------------------------------------------------------- // Support macro for defining builtins in C++. // ---------------------------------------------------------------------------- // // A builtin function is defined by writing: // // BUILTIN(name) { // ... // } // // In the body of the builtin function the arguments can be accessed // through the BuiltinArguments object args. #define BUILTIN(name) \ MUST_USE_RESULT static Object* Builtin_Impl_##name( \ name##ArgumentsType args, Isolate* isolate); \ MUST_USE_RESULT static Object* Builtin_##name( \ int args_length, Object** args_object, Isolate* isolate) { \ name##ArgumentsType args(args_length, args_object); \ return Builtin_Impl_##name(args, isolate); \ } \ MUST_USE_RESULT static Object* Builtin_Impl_##name( \ name##ArgumentsType args, Isolate* isolate) // ---------------------------------------------------------------------------- #define CHECK_RECEIVER(Type, name, method) \ if (!args.receiver()->Is##Type()) { \ THROW_NEW_ERROR_RETURN_FAILURE( \ isolate, \ NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, \ isolate->factory()->NewStringFromAsciiChecked(method), \ args.receiver())); \ } \ Handle
name = Handle
::cast(args.receiver()) 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()) { 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
(value); } return true; } else if (object->IsUndefined() || object->IsNull()) { *out = 0; return true; } else if (object->IsBoolean()) { *out = object->IsTrue(); return true; } return false; } inline bool GetSloppyArgumentsLength(Isolate* isolate, Handle
object, int* out) { Map* arguments_map = isolate->native_context()->sloppy_arguments_map(); if (object->map() != arguments_map) return false; DCHECK(object->HasFastElements()); Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex); if (!len_obj->IsSmi()) return false; *out = Max(0, Smi::cast(len_obj)->value()); return *out <= object->elements()->length(); } inline bool PrototypeHasNoElements(PrototypeIterator* iter) { DisallowHeapAllocation no_gc; for (; !iter->IsAtEnd(); iter->Advance()) { if (iter->GetCurrent()->IsJSProxy()) return false; JSObject* current = iter->GetCurrent
(); if (current->IsAccessCheckNeeded()) return false; if (current->HasIndexedInterceptor()) return false; if (current->elements()->length() != 0) return false; } return true; } 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. Object* prototype = receiver->map()->prototype(); if (prototype->IsJSArray() && isolate->is_initial_array_prototype(JSArray::cast(prototype)) && isolate->IsFastArrayConstructorPrototypeChainIntact()) { return true; } // Slow case. PrototypeIterator iter(isolate, receiver); return PrototypeHasNoElements(&iter); } // Returns empty handle if not applicable. MUST_USE_RESULT inline MaybeHandle
EnsureJSArrayWithWritableFastElements( Isolate* isolate, Handle
receiver, Arguments* args, int first_added_arg) { if (!receiver->IsJSArray()) return MaybeHandle
(); Handle
array = Handle
::cast(receiver); // If there may be elements accessors in the prototype chain, the fast path // cannot be used if there arguments to add to the array. Heap* heap = isolate->heap(); if (args != NULL && !IsJSArrayFastElementMovingAllowed(isolate, *array)) { return MaybeHandle
(); } if (array->map()->is_observed()) return MaybeHandle
(); if (!array->map()->is_extensible()) return MaybeHandle
(); Handle
elms(array->elements(), isolate); Map* map = elms->map(); if (map == heap->fixed_array_map()) { if (args == NULL || array->HasFastObjectElements()) return elms; } else if (map == heap->fixed_cow_array_map()) { elms = JSObject::EnsureWritableFastElements(array); if (args == NULL || array->HasFastObjectElements()) return elms; } else if (map == heap->fixed_double_array_map()) { if (args == NULL) return elms; } else { return MaybeHandle
(); } // Adding elements to the array prototype would break code that makes sure // it has no elements. Handle that elsewhere. if (isolate->IsAnyInitialArrayPrototype(array)) { return MaybeHandle
(); } // Need to ensure that the arguments passed in args can be contained in // the array. int args_length = args->length(); if (first_added_arg >= args_length) return handle(array->elements(), isolate); ElementsKind origin_kind = array->map()->elements_kind(); DCHECK(!IsFastObjectElementsKind(origin_kind)); ElementsKind target_kind = origin_kind; { DisallowHeapAllocation no_gc; int arg_count = args_length - first_added_arg; Object** arguments = args->arguments() - first_added_arg - (arg_count - 1); for (int i = 0; i < arg_count; i++) { Object* arg = arguments[i]; if (arg->IsHeapObject()) { if (arg->IsHeapNumber()) { target_kind = FAST_DOUBLE_ELEMENTS; } else { target_kind = FAST_ELEMENTS; break; } } } } if (target_kind != origin_kind) { JSObject::TransitionElementsKind(array, target_kind); return handle(array->elements(), isolate); } return elms; } MUST_USE_RESULT static Object* CallJsIntrinsic( Isolate* isolate, Handle
function, BuiltinArguments
args) { HandleScope handleScope(isolate); int argc = args.length() - 1; ScopedVector
> argv(argc); for (int i = 0; i < argc; ++i) { argv[i] = args.at
(i + 1); } Handle
result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, Execution::Call(isolate, function, args.receiver(), argc, argv.start())); return *result; } } // namespace BUILTIN(Illegal) { UNREACHABLE(); return isolate->heap()->undefined_value(); // Make compiler happy. } BUILTIN(EmptyFunction) { return isolate->heap()->undefined_value(); } BUILTIN(ArrayPush) { HandleScope scope(isolate); Handle
receiver = args.receiver(); MaybeHandle
maybe_elms_obj = EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1); Handle
elms_obj; if (!maybe_elms_obj.ToHandle(&elms_obj)) { return CallJsIntrinsic(isolate, isolate->array_push(), args); } // Fast Elements Path int push_size = args.length() - 1; Handle
array = Handle
::cast(receiver); int len = Smi::cast(array->length())->value(); if (push_size == 0) { return Smi::FromInt(len); } if (push_size > 0 && JSArray::WouldChangeReadOnlyLength(array, len + push_size)) { return CallJsIntrinsic(isolate, isolate->array_push(), args); } DCHECK(!array->map()->is_observed()); ElementsAccessor* accessor = array->GetElementsAccessor(); int new_length = accessor->Push(array, elms_obj, &args, push_size); return Smi::FromInt(new_length); } BUILTIN(ArrayPop) { HandleScope scope(isolate); Handle
receiver = args.receiver(); MaybeHandle
maybe_elms_obj = EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); Handle
elms_obj; if (!maybe_elms_obj.ToHandle(&elms_obj)) { return CallJsIntrinsic(isolate, isolate->array_pop(), args); } Handle
array = Handle
::cast(receiver); DCHECK(!array->map()->is_observed()); uint32_t len = static_cast
(Smi::cast(array->length())->value()); if (len == 0) return isolate->heap()->undefined_value(); if (JSArray::HasReadOnlyLength(array)) { return CallJsIntrinsic(isolate, isolate->array_pop(), args); } Handle
result; if (IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) { // Fast Elements Path result = array->GetElementsAccessor()->Pop(array, elms_obj); } else { // Use Slow Lookup otherwise uint32_t new_length = len - 1; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, Object::GetElement(isolate, array, new_length)); JSArray::SetLength(array, new_length); } return *result; } BUILTIN(ArrayShift) { HandleScope scope(isolate); Heap* heap = isolate->heap(); Handle
receiver = args.receiver(); MaybeHandle
maybe_elms_obj = EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); Handle
elms_obj; if (!maybe_elms_obj.ToHandle(&elms_obj) || !IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) { return CallJsIntrinsic(isolate, isolate->array_shift(), args); } Handle
array = Handle
::cast(receiver); DCHECK(!array->map()->is_observed()); int len = Smi::cast(array->length())->value(); if (len == 0) return heap->undefined_value(); if (JSArray::HasReadOnlyLength(array)) { return CallJsIntrinsic(isolate, isolate->array_shift(), args); } Handle
first = array->GetElementsAccessor()->Shift(array, elms_obj); return *first; } BUILTIN(ArrayUnshift) { HandleScope scope(isolate); Handle
receiver = args.receiver(); MaybeHandle
maybe_elms_obj = EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1); Handle
elms_obj; if (!maybe_elms_obj.ToHandle(&elms_obj)) { return CallJsIntrinsic(isolate, isolate->array_unshift(), args); } Handle
array = Handle
::cast(receiver); DCHECK(!array->map()->is_observed()); int to_add = args.length() - 1; if (to_add == 0) { return array->length(); } // Currently fixed arrays cannot grow too big, so // we should never hit this case. DCHECK(to_add <= (Smi::kMaxValue - Smi::cast(array->length())->value())); if (to_add > 0 && JSArray::HasReadOnlyLength(array)) { return CallJsIntrinsic(isolate, isolate->array_unshift(), args); } ElementsAccessor* accessor = array->GetElementsAccessor(); int new_length = accessor->Unshift(array, elms_obj, &args, to_add); return Smi::FromInt(new_length); } BUILTIN(ArraySlice) { HandleScope scope(isolate); Handle
receiver = args.receiver(); Handle
object; Handle
elms_obj; int len = -1; int relative_start = 0; int relative_end = 0; bool is_sloppy_arguments = false; // TODO(littledan): Look up @@species only once, not once here and // again in the JS builtin. Pass the species out? Handle
species; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, species, Object::ArraySpeciesConstructor(isolate, receiver)); if (*species != isolate->context()->native_context()->array_function()) { 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); } len = Smi::cast(array->length())->value(); object = Handle
::cast(receiver); elms_obj = handle(array->elements(), isolate); } else if (receiver->IsJSObject() && GetSloppyArgumentsLength(isolate, Handle
::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
::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); } } } // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. 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. uint32_t actual_end = (relative_end < 0) ? Max(len + relative_end, 0) : Min(relative_end, len); if (actual_end <= actual_start) { Handle
result_array = isolate->factory()->NewJSArray( GetPackedElementsKind(object->GetElementsKind()), 0, 0); return *result_array; } 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
result_array = accessor->Slice(object, elms_obj, actual_start, actual_end); return *result_array; } BUILTIN(ArraySplice) { HandleScope scope(isolate); Handle
receiver = args.receiver(); MaybeHandle
maybe_elms_obj = EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); Handle
elms_obj; if (!maybe_elms_obj.ToHandle(&elms_obj)) { return CallJsIntrinsic(isolate, isolate->array_splice(), args); } // TODO(littledan): Look up @@species only once, not once here and // again in the JS builtin. Pass the species out? Handle
species; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, species, Object::ArraySpeciesConstructor(isolate, receiver)); if (*species != isolate->context()->native_context()->array_function()) { return CallJsIntrinsic(isolate, isolate->array_splice(), args); } Handle
array = Handle
::cast(receiver); DCHECK(!array->map()->is_observed()); int argument_count = args.length() - 1; int relative_start = 0; if (argument_count > 0) { DisallowHeapAllocation no_gc; if (!ClampedToInteger(args[1], &relative_start)) { AllowHeapAllocation allow_allocation; return CallJsIntrinsic(isolate, isolate->array_splice(), args); } } int len = Smi::cast(array->length())->value(); // clip relative start to [0, len] int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) : Min(relative_start, len); int actual_delete_count; if (argument_count == 1) { // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is // given as a request to delete all the elements from the start. // And it differs from the case of undefined delete count. // This does not follow ECMA-262, but we do the same for compatibility. DCHECK(len - actual_start >= 0); actual_delete_count = len - actual_start; } else { int delete_count = 0; DisallowHeapAllocation no_gc; if (argument_count > 1) { if (!ClampedToInteger(args[2], &delete_count)) { AllowHeapAllocation allow_allocation; return CallJsIntrinsic(isolate, isolate->array_splice(), args); } } actual_delete_count = Min(Max(delete_count, 0), len - actual_start); } int add_count = (argument_count > 1) ? (argument_count - 2) : 0; int new_length = len - actual_delete_count + add_count; if (new_length != len && JSArray::HasReadOnlyLength(array)) { AllowHeapAllocation allow_allocation; return CallJsIntrinsic(isolate, isolate->array_splice(), args); } ElementsAccessor* accessor = array->GetElementsAccessor(); Handle
result_array = accessor->Splice( array, elms_obj, actual_start, actual_delete_count, &args, add_count); return *result_array; } // Array Concat ------------------------------------------------------------- namespace { /** * A simple visitor visits every element of Array's. * The backend storage can be a fixed array for fast elements case, * or a dictionary for sparse array. Since Dictionary is a subtype * of FixedArray, the class can be used by both fast and slow cases. * The second parameter of the constructor, fast_elements, specifies * whether the storage is a FixedArray or Dictionary. * * An index limit is used to deal with the situation that a result array * length overflows 32-bit non-negative integer. */ class ArrayConcatVisitor { public: ArrayConcatVisitor(Isolate* isolate, Handle
storage, bool fast_elements) : isolate_(isolate), storage_(Handle
::cast( isolate->global_handles()->Create(*storage))), index_offset_(0u), bit_field_(FastElementsField::encode(fast_elements) | ExceedsLimitField::encode(false)) {} ~ArrayConcatVisitor() { clear_storage(); } void visit(uint32_t i, Handle
elm) { if (i >= JSObject::kMaxElementCount - index_offset_) { set_exceeds_array_limit(true); return; } uint32_t index = index_offset_ + i; if (fast_elements()) { if (index < static_cast
(storage_->length())) { storage_->set(index, *elm); return; } // Our initial estimate of length was foiled, possibly by // getters on the arrays increasing the length of later arrays // during iteration. // This shouldn't happen in anything but pathological cases. SetDictionaryMode(); // Fall-through to dictionary mode. } DCHECK(!fast_elements()); Handle
dict( SeededNumberDictionary::cast(*storage_)); // The object holding this backing store has just been allocated, so // it cannot yet be used as a prototype. Handle
result = SeededNumberDictionary::AtNumberPut(dict, index, elm, false); if (!result.is_identical_to(dict)) { // Dictionary needed to grow. clear_storage(); set_storage(*result); } } void increase_index_offset(uint32_t delta) { if (JSObject::kMaxElementCount - index_offset_ < delta) { index_offset_ = JSObject::kMaxElementCount; } else { index_offset_ += delta; } // If the initial length estimate was off (see special case in visit()), // but the array blowing the limit didn't contain elements beyond the // provided-for index range, go to dictionary mode now. if (fast_elements() && index_offset_ > static_cast
(FixedArrayBase::cast(*storage_)->length())) { SetDictionaryMode(); } } bool exceeds_array_limit() const { return ExceedsLimitField::decode(bit_field_); } Handle
ToArray() { Handle
array = isolate_->factory()->NewJSArray(0); Handle
length = isolate_->factory()->NewNumber(static_cast
(index_offset_)); Handle
map = JSObject::GetElementsTransitionMap( array, fast_elements() ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS); array->set_map(*map); array->set_length(*length); array->set_elements(*storage_); return array; } private: // Convert storage to dictionary mode. void SetDictionaryMode() { DCHECK(fast_elements()); Handle
current_storage(*storage_); Handle
slow_storage( SeededNumberDictionary::New(isolate_, current_storage->length())); uint32_t current_length = static_cast
(current_storage->length()); for (uint32_t i = 0; i < current_length; i++) { HandleScope loop_scope(isolate_); Handle
element(current_storage->get(i), isolate_); if (!element->IsTheHole()) { // The object holding this backing store has just been allocated, so // it cannot yet be used as a prototype. Handle
new_storage = SeededNumberDictionary::AtNumberPut(slow_storage, i, element, false); if (!new_storage.is_identical_to(slow_storage)) { slow_storage = loop_scope.CloseAndEscape(new_storage); } } } clear_storage(); set_storage(*slow_storage); set_fast_elements(false); } inline void clear_storage() { GlobalHandles::Destroy(Handle
::cast(storage_).location()); } inline void set_storage(FixedArray* storage) { storage_ = Handle
::cast(isolate_->global_handles()->Create(storage)); } class FastElementsField : public BitField
{}; class ExceedsLimitField : public BitField
{}; bool fast_elements() const { return FastElementsField::decode(bit_field_); } void set_fast_elements(bool fast) { bit_field_ = FastElementsField::update(bit_field_, fast); } void set_exceeds_array_limit(bool exceeds) { bit_field_ = ExceedsLimitField::update(bit_field_, exceeds); } Isolate* isolate_; Handle
storage_; // Always a global handle. // Index after last seen index. Always less than or equal to // JSObject::kMaxElementCount. uint32_t index_offset_; uint32_t bit_field_; }; uint32_t EstimateElementCount(Handle
array) { uint32_t length = static_cast
(array->length()->Number()); int element_count = 0; switch (array->GetElementsKind()) { case FAST_SMI_ELEMENTS: case FAST_HOLEY_SMI_ELEMENTS: case FAST_ELEMENTS: case FAST_HOLEY_ELEMENTS: { // Fast elements can't have lengths that are not representable by // a 32-bit signed integer. DCHECK(static_cast
(FixedArray::kMaxLength) >= 0); int fast_length = static_cast
(length); Handle
elements(FixedArray::cast(array->elements())); for (int i = 0; i < fast_length; i++) { if (!elements->get(i)->IsTheHole()) element_count++; } break; } case FAST_DOUBLE_ELEMENTS: case FAST_HOLEY_DOUBLE_ELEMENTS: { // Fast elements can't have lengths that are not representable by // a 32-bit signed integer. DCHECK(static_cast
(FixedDoubleArray::kMaxLength) >= 0); int fast_length = static_cast
(length); if (array->elements()->IsFixedArray()) { DCHECK(FixedArray::cast(array->elements())->length() == 0); break; } Handle
elements( FixedDoubleArray::cast(array->elements())); for (int i = 0; i < fast_length; i++) { if (!elements->is_the_hole(i)) element_count++; } break; } case DICTIONARY_ELEMENTS: { Handle
dictionary( SeededNumberDictionary::cast(array->elements())); int capacity = dictionary->Capacity(); for (int i = 0; i < capacity; i++) { Handle
key(dictionary->KeyAt(i), array->GetIsolate()); if (dictionary->IsKey(*key)) { element_count++; } } break; } case FAST_SLOPPY_ARGUMENTS_ELEMENTS: case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS: TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE // External arrays are always dense. return length; } // As an estimate, we assume that the prototype doesn't contain any // inherited elements. return element_count; } template
void IterateTypedArrayElements(Isolate* isolate, Handle
receiver, bool elements_are_ints, bool elements_are_guaranteed_smis, ArrayConcatVisitor* visitor) { Handle
array( ExternalArrayClass::cast(receiver->elements())); uint32_t len = static_cast
(array->length()); DCHECK(visitor != NULL); if (elements_are_ints) { if (elements_are_guaranteed_smis) { for (uint32_t j = 0; j < len; j++) { HandleScope loop_scope(isolate); Handle
e(Smi::FromInt(static_cast
(array->get_scalar(j))), isolate); visitor->visit(j, e); } } else { for (uint32_t j = 0; j < len; j++) { HandleScope loop_scope(isolate); int64_t val = static_cast
(array->get_scalar(j)); if (Smi::IsValid(static_cast
(val))) { Handle
e(Smi::FromInt(static_cast
(val)), isolate); visitor->visit(j, e); } else { Handle
e = isolate->factory()->NewNumber(static_cast
(val)); visitor->visit(j, e); } } } } else { for (uint32_t j = 0; j < len; j++) { HandleScope loop_scope(isolate); Handle
e = isolate->factory()->NewNumber(array->get_scalar(j)); visitor->visit(j, e); } } } // Used for sorting indices in a List
. int compareUInt32(const uint32_t* ap, const uint32_t* bp) { uint32_t a = *ap; uint32_t b = *bp; return (a == b) ? 0 : (a < b) ? -1 : 1; } void CollectElementIndices(Handle
object, uint32_t range, List
* indices) { Isolate* isolate = object->GetIsolate(); ElementsKind kind = object->GetElementsKind(); switch (kind) { case FAST_SMI_ELEMENTS: case FAST_ELEMENTS: case FAST_HOLEY_SMI_ELEMENTS: case FAST_HOLEY_ELEMENTS: { Handle
elements(FixedArray::cast(object->elements())); uint32_t length = static_cast
(elements->length()); if (range < length) length = range; for (uint32_t i = 0; i < length; i++) { if (!elements->get(i)->IsTheHole()) { indices->Add(i); } } break; } case FAST_HOLEY_DOUBLE_ELEMENTS: case FAST_DOUBLE_ELEMENTS: { if (object->elements()->IsFixedArray()) { DCHECK(object->elements()->length() == 0); break; } Handle
elements( FixedDoubleArray::cast(object->elements())); uint32_t length = static_cast
(elements->length()); if (range < length) length = range; for (uint32_t i = 0; i < length; i++) { if (!elements->is_the_hole(i)) { indices->Add(i); } } break; } case DICTIONARY_ELEMENTS: { Handle
dict( SeededNumberDictionary::cast(object->elements())); uint32_t capacity = dict->Capacity(); for (uint32_t j = 0; j < capacity; j++) { HandleScope loop_scope(isolate); Handle
k(dict->KeyAt(j), isolate); if (dict->IsKey(*k)) { DCHECK(k->IsNumber()); uint32_t index = static_cast
(k->Number()); if (index < range) { indices->Add(index); } } } break; } #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS: TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE { uint32_t length = static_cast
( FixedArrayBase::cast(object->elements())->length()); if (range <= length) { length = range; // We will add all indices, so we might as well clear it first // and avoid duplicates. indices->Clear(); } for (uint32_t i = 0; i < length; i++) { indices->Add(i); } if (length == range) return; // All indices accounted for already. break; } case FAST_SLOPPY_ARGUMENTS_ELEMENTS: case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { ElementsAccessor* accessor = object->GetElementsAccessor(); for (uint32_t i = 0; i < range; i++) { if (accessor->HasElement(object, i)) { indices->Add(i); } } break; } } PrototypeIterator iter(isolate, object); if (!iter.IsAtEnd()) { // The prototype will usually have no inherited element indices, // but we have to check. CollectElementIndices(PrototypeIterator::GetCurrent
(iter), range, indices); } } bool IterateElementsSlow(Isolate* isolate, Handle
receiver, uint32_t length, ArrayConcatVisitor* visitor) { for (uint32_t i = 0; i < length; ++i) { HandleScope loop_scope(isolate); Maybe
maybe = JSReceiver::HasElement(receiver, i); if (!maybe.IsJust()) return false; if (maybe.FromJust()) { Handle
element_value; ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_value, Object::GetElement(isolate, receiver, i), false); visitor->visit(i, element_value); } } visitor->increase_index_offset(length); return true; } /** * A helper function that visits "array" elements of a JSReceiver in numerical * order. * * The visitor argument called for each existing element in the array * with the element index and the element's value. * Afterwards it increments the base-index of the visitor by the array * length. * Returns false if any access threw an exception, otherwise true. */ bool IterateElements(Isolate* isolate, Handle
receiver, ArrayConcatVisitor* visitor) { uint32_t length = 0; if (receiver->IsJSArray()) { Handle
array = Handle
::cast(receiver); length = static_cast
(array->length()->Number()); } else { Handle
val; Handle
key = isolate->factory()->length_string(); ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, val, Runtime::GetObjectProperty(isolate, receiver, key), false); ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, val, Object::ToLength(isolate, val), false); // TODO(caitp): Support larger element indexes (up to 2^53-1). if (!val->ToUint32(&length)) { length = 0; } } if (!(receiver->IsJSArray() || receiver->IsJSTypedArray())) { // For classes which are not known to be safe to access via elements alone, // use the slow case. return IterateElementsSlow(isolate, receiver, length, visitor); } Handle
array = Handle
::cast(receiver); switch (array->GetElementsKind()) { case FAST_SMI_ELEMENTS: case FAST_ELEMENTS: case FAST_HOLEY_SMI_ELEMENTS: case FAST_HOLEY_ELEMENTS: { // Run through the elements FixedArray and use HasElement and GetElement // to check the prototype for missing elements. Handle
elements(FixedArray::cast(array->elements())); int fast_length = static_cast
(length); DCHECK(fast_length <= elements->length()); for (int j = 0; j < fast_length; j++) { HandleScope loop_scope(isolate); Handle
element_value(elements->get(j), isolate); if (!element_value->IsTheHole()) { visitor->visit(j, element_value); } else { Maybe
maybe = JSReceiver::HasElement(array, j); if (!maybe.IsJust()) return false; if (maybe.FromJust()) { // Call GetElement on array, not its prototype, or getters won't // have the correct receiver. ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, element_value, Object::GetElement(isolate, array, j), false); visitor->visit(j, element_value); } } } break; } case FAST_HOLEY_DOUBLE_ELEMENTS: case FAST_DOUBLE_ELEMENTS: { // Empty array is FixedArray but not FixedDoubleArray. if (length == 0) break; // Run through the elements FixedArray and use HasElement and GetElement // to check the prototype for missing elements. if (array->elements()->IsFixedArray()) { DCHECK(array->elements()->length() == 0); break; } Handle
elements( FixedDoubleArray::cast(array->elements())); int fast_length = static_cast
(length); DCHECK(fast_length <= elements->length()); for (int j = 0; j < fast_length; j++) { HandleScope loop_scope(isolate); if (!elements->is_the_hole(j)) { double double_value = elements->get_scalar(j); Handle
element_value = isolate->factory()->NewNumber(double_value); visitor->visit(j, element_value); } else { Maybe
maybe = JSReceiver::HasElement(array, j); if (!maybe.IsJust()) return false; if (maybe.FromJust()) { // Call GetElement on array, not its prototype, or getters won't // have the correct receiver. Handle
element_value; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, element_value, Object::GetElement(isolate, array, j), false); visitor->visit(j, element_value); } } } break; } case DICTIONARY_ELEMENTS: { // CollectElementIndices() can't be called when there's a JSProxy // on the prototype chain. for (PrototypeIterator iter(isolate, array); !iter.IsAtEnd(); iter.Advance()) { if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { return IterateElementsSlow(isolate, array, length, visitor); } } Handle
dict(array->element_dictionary()); List
indices(dict->Capacity() / 2); // Collect all indices in the object and the prototypes less // than length. This might introduce duplicates in the indices list. CollectElementIndices(array, length, &indices); indices.Sort(&compareUInt32); int j = 0; int n = indices.length(); while (j < n) { HandleScope loop_scope(isolate); uint32_t index = indices[j]; Handle
element; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, element, Object::GetElement(isolate, array, index), false); visitor->visit(index, element); // Skip to next different index (i.e., omit duplicates). do { j++; } while (j < n && indices[j] == index); } break; } case UINT8_CLAMPED_ELEMENTS: { Handle
pixels( FixedUint8ClampedArray::cast(array->elements())); for (uint32_t j = 0; j < length; j++) { Handle
e(Smi::FromInt(pixels->get_scalar(j)), isolate); visitor->visit(j, e); } break; } case INT8_ELEMENTS: { IterateTypedArrayElements
(isolate, array, true, true, visitor); break; } case UINT8_ELEMENTS: { IterateTypedArrayElements
(isolate, array, true, true, visitor); break; } case INT16_ELEMENTS: { IterateTypedArrayElements
(isolate, array, true, true, visitor); break; } case UINT16_ELEMENTS: { IterateTypedArrayElements
( isolate, array, true, true, visitor); break; } case INT32_ELEMENTS: { IterateTypedArrayElements
(isolate, array, true, false, visitor); break; } case UINT32_ELEMENTS: { IterateTypedArrayElements
( isolate, array, true, false, visitor); break; } case FLOAT32_ELEMENTS: { IterateTypedArrayElements
(isolate, array, false, false, visitor); break; } case FLOAT64_ELEMENTS: { IterateTypedArrayElements
( isolate, array, false, false, visitor); break; } case FAST_SLOPPY_ARGUMENTS_ELEMENTS: case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { for (uint32_t index = 0; index < length; index++) { HandleScope loop_scope(isolate); Handle
element; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, element, Object::GetElement(isolate, array, index), false); visitor->visit(index, element); } break; } } visitor->increase_index_offset(length); return true; } bool HasConcatSpreadableModifier(Isolate* isolate, Handle
obj) { DCHECK(isolate->IsFastArrayConstructorPrototypeChainIntact()); if (!FLAG_harmony_concat_spreadable) return false; Handle
key(isolate->factory()->is_concat_spreadable_symbol()); Maybe
maybe = JSReceiver::HasProperty(obj, key); return maybe.FromMaybe(false); } static Maybe
IsConcatSpreadable(Isolate* isolate, Handle
obj) { HandleScope handle_scope(isolate); if (!obj->IsJSReceiver()) return Just(false); if (FLAG_harmony_concat_spreadable) { Handle
key(isolate->factory()->is_concat_spreadable_symbol()); Handle
value; MaybeHandle
maybeValue = i::Runtime::GetObjectProperty(isolate, obj, key); if (!maybeValue.ToHandle(&value)) return Nothing
(); if (!value->IsUndefined()) return Just(value->BooleanValue()); } return Object::IsArray(obj); } Object* Slow_ArrayConcat(Arguments* args, Isolate* isolate) { int argument_count = args->length(); // Pass 1: estimate the length and number of elements of the result. // The actual length can be larger if any of the arguments have getters // that mutate other arguments (but will otherwise be precise). // The number of elements is precise if there are no inherited elements. ElementsKind kind = FAST_SMI_ELEMENTS; uint32_t estimate_result_length = 0; uint32_t estimate_nof_elements = 0; for (int i = 0; i < argument_count; i++) { HandleScope loop_scope(isolate); Handle
obj((*args)[i], isolate); uint32_t length_estimate; uint32_t element_estimate; if (obj->IsJSArray()) { Handle
array(Handle
::cast(obj)); length_estimate = static_cast
(array->length()->Number()); if (length_estimate != 0) { ElementsKind array_kind = GetPackedElementsKind(array->map()->elements_kind()); kind = GetMoreGeneralElementsKind(kind, array_kind); } element_estimate = EstimateElementCount(array); } else { if (obj->IsHeapObject()) { if (obj->IsNumber()) { kind = GetMoreGeneralElementsKind(kind, FAST_DOUBLE_ELEMENTS); } else { kind = GetMoreGeneralElementsKind(kind, FAST_ELEMENTS); } } length_estimate = 1; element_estimate = 1; } // Avoid overflows by capping at kMaxElementCount. if (JSObject::kMaxElementCount - estimate_result_length < length_estimate) { estimate_result_length = JSObject::kMaxElementCount; } else { estimate_result_length += length_estimate; } if (JSObject::kMaxElementCount - estimate_nof_elements < element_estimate) { estimate_nof_elements = JSObject::kMaxElementCount; } else { estimate_nof_elements += element_estimate; } } // If estimated number of elements is more than half of length, a // fixed array (fast case) is more time and space-efficient than a // dictionary. bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length; if (fast_case && kind == FAST_DOUBLE_ELEMENTS) { Handle
storage = isolate->factory()->NewFixedDoubleArray(estimate_result_length); int j = 0; bool failure = false; if (estimate_result_length > 0) { Handle
double_storage = Handle
::cast(storage); for (int i = 0; i < argument_count; i++) { Handle
obj((*args)[i], isolate); if (obj->IsSmi()) { double_storage->set(j, Smi::cast(*obj)->value()); j++; } else if (obj->IsNumber()) { double_storage->set(j, obj->Number()); j++; } else { JSArray* array = JSArray::cast(*obj); uint32_t length = static_cast
(array->length()->Number()); switch (array->map()->elements_kind()) { case FAST_HOLEY_DOUBLE_ELEMENTS: case FAST_DOUBLE_ELEMENTS: { // Empty array is FixedArray but not FixedDoubleArray. if (length == 0) break; FixedDoubleArray* elements = FixedDoubleArray::cast(array->elements()); for (uint32_t i = 0; i < length; i++) { if (elements->is_the_hole(i)) { // TODO(jkummerow/verwaest): We could be a bit more clever // here: Check if there are no elements/getters on the // prototype chain, and if so, allow creation of a holey // result array. // Same thing below (holey smi case). failure = true; break; } double double_value = elements->get_scalar(i); double_storage->set(j, double_value); j++; } break; } case FAST_HOLEY_SMI_ELEMENTS: case FAST_SMI_ELEMENTS: { FixedArray* elements(FixedArray::cast(array->elements())); for (uint32_t i = 0; i < length; i++) { Object* element = elements->get(i); if (element->IsTheHole()) { failure = true; break; } int32_t int_value = Smi::cast(element)->value(); double_storage->set(j, int_value); j++; } break; } case FAST_HOLEY_ELEMENTS: case FAST_ELEMENTS: case DICTIONARY_ELEMENTS: DCHECK_EQ(0u, length); break; default: UNREACHABLE(); } } if (failure) break; } } if (!failure) { Handle
array = isolate->factory()->NewJSArray(0); Smi* length = Smi::FromInt(j); Handle
map; map = JSObject::GetElementsTransitionMap(array, kind); array->set_map(*map); array->set_length(length); array->set_elements(*storage); return *array; } // In case of failure, fall through. } Handle
storage; if (fast_case) { // The backing storage array must have non-existing elements to preserve // holes across concat operations. storage = isolate->factory()->NewFixedArrayWithHoles(estimate_result_length); } else { // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate uint32_t at_least_space_for = estimate_nof_elements + (estimate_nof_elements >> 2); storage = Handle
::cast( SeededNumberDictionary::New(isolate, at_least_space_for)); } ArrayConcatVisitor visitor(isolate, storage, fast_case); for (int i = 0; i < argument_count; i++) { Handle
obj((*args)[i], isolate); Maybe
spreadable = IsConcatSpreadable(isolate, obj); MAYBE_RETURN(spreadable, isolate->heap()->exception()); if (spreadable.FromJust()) { Handle
object = Handle
::cast(obj); if (!IterateElements(isolate, object, &visitor)) { return isolate->heap()->exception(); } } else { visitor.visit(0, obj); visitor.increase_index_offset(1); } } if (visitor.exceeds_array_limit()) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewRangeError(MessageTemplate::kInvalidArrayLength)); } return *visitor.ToArray(); } MaybeHandle
Fast_ArrayConcat(Isolate* isolate, Arguments* args) { if (!isolate->IsFastArrayConstructorPrototypeChainIntact()) { return MaybeHandle
(); } int n_arguments = args->length(); int result_len = 0; { DisallowHeapAllocation no_gc; Object* array_proto = isolate->array_function()->prototype(); // Iterate through all the arguments performing checks // and calculating total length. for (int i = 0; i < n_arguments; i++) { Object* arg = (*args)[i]; if (!arg->IsJSArray()) return MaybeHandle
(); Handle
array(JSArray::cast(arg), isolate); if (!array->HasFastElements()) return MaybeHandle
(); PrototypeIterator iter(isolate, arg); if (iter.GetCurrent() != array_proto) return MaybeHandle
(); if (HasConcatSpreadableModifier(isolate, array)) { return MaybeHandle
(); } int len = Smi::cast(array->length())->value(); // We shouldn't overflow when adding another len. const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); USE(kHalfOfMaxInt); result_len += len; DCHECK(result_len >= 0); // Throw an Error if we overflow the FixedArray limits if (FixedArray::kMaxLength < result_len) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength), JSArray); } } } return ElementsAccessor::Concat(isolate, args, n_arguments); } } // namespace // ES6 22.1.3.1 Array.prototype.concat BUILTIN(ArrayConcat) { HandleScope scope(isolate); Handle
receiver; if (!Object::ToObject(isolate, handle(args[0], isolate)) .ToHandle(&receiver)) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, isolate->factory()->NewStringFromAsciiChecked( "Array.prototype.concat"))); } args[0] = *receiver; Handle
result_array; if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) { return *result_array; } if (isolate->has_pending_exception()) return isolate->heap()->exception(); return Slow_ArrayConcat(&args, isolate); } // ES6 22.1.2.2 Array.isArray BUILTIN(ArrayIsArray) { HandleScope scope(isolate); DCHECK_EQ(2, args.length()); Handle
object = args.at
(1); Maybe
result = Object::IsArray(object); MAYBE_RETURN(result, isolate->heap()->exception()); return *isolate->factory()->ToBoolean(result.FromJust()); } // ES6 19.1.2.1 Object.assign BUILTIN(ObjectAssign) { HandleScope scope(isolate); Handle
target = args.atOrUndefined(isolate, 1); // 1. Let to be ? ToObject(target). ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target, Execution::ToObject(isolate, target)); Handle
to = Handle
::cast(target); // 2. If only one argument was passed, return to. if (args.length() == 2) return *to; // 3. Let sources be the List of argument values starting with the // second argument. // 4. For each element nextSource of sources, in ascending index order, for (int i = 2; i < args.length(); ++i) { Handle
next_source = args.at
(i); // 4a. If nextSource is undefined or null, let keys be an empty List. if (next_source->IsUndefined() || next_source->IsNull()) continue; // 4b. Else, // 4b i. Let from be ToObject(nextSource). Handle
from = Object::ToObject(isolate, next_source).ToHandleChecked(); // 4b ii. Let keys be ? from.[[OwnPropertyKeys]](). Handle
keys; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, keys, JSReceiver::GetKeys(from, JSReceiver::OWN_ONLY, ALL_PROPERTIES, KEEP_NUMBERS)); // 4c. Repeat for each element nextKey of keys in List order, for (int j = 0; j < keys->length(); ++j) { Handle
next_key(keys->get(j), isolate); // 4c i. Let desc be ? from.[[GetOwnProperty]](nextKey). PropertyDescriptor desc; Maybe
found = JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc); if (found.IsNothing()) return isolate->heap()->exception(); // 4c ii. If desc is not undefined and desc.[[Enumerable]] is true, then if (found.FromJust() && desc.enumerable()) { // 4c ii 1. Let propValue be ? Get(from, nextKey). Handle
prop_value; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, prop_value, Runtime::GetObjectProperty(isolate, from, next_key, STRICT)); // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true). Handle
status; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, status, Runtime::SetObjectProperty(isolate, to, next_key, prop_value, STRICT)); } } } // 5. Return to. return *to; } // ES6 section 19.1.2.2 Object.create ( O [ , Properties ] ) BUILTIN(ObjectCreate) { HandleScope scope(isolate); Handle
prototype = args.atOrUndefined(isolate, 1); if (!prototype->IsNull() && !prototype->IsJSReceiver()) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, prototype)); } // Generate the map with the specified {prototype} based on the Object // function's initial map from the current native context. // TODO(bmeurer): Use a dedicated cache for Object.create; think about // slack tracking for Object.create. Handle
map(isolate->native_context()->object_function()->initial_map(), isolate); if (map->prototype() != *prototype) { map = Map::TransitionToPrototype(map, prototype, FAST_PROTOTYPE); } // Actually allocate the object. Handle
object = isolate->factory()->NewJSObjectFromMap(map); // Define the properties if properties was specified and is not undefined. Handle
properties = args.atOrUndefined(isolate, 2); if (!properties->IsUndefined()) { RETURN_FAILURE_ON_EXCEPTION( isolate, JSReceiver::DefineProperties(isolate, object, properties)); } return *object; } // ES6 section 19.1.2.5 Object.freeze ( O ) BUILTIN(ObjectFreeze) { HandleScope scope(isolate); Handle
object = args.atOrUndefined(isolate, 1); if (object->IsJSReceiver()) { MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle
::cast(object), FROZEN, Object::THROW_ON_ERROR), isolate->heap()->exception()); } return *object; } // ES6 section 19.1.2.11 Object.isExtensible ( O ) BUILTIN(ObjectIsExtensible) { HandleScope scope(isolate); Handle
object = args.atOrUndefined(isolate, 1); Maybe
result = object->IsJSReceiver() ? JSReceiver::IsExtensible(Handle
::cast(object)) : Just(false); MAYBE_RETURN(result, isolate->heap()->exception()); return isolate->heap()->ToBoolean(result.FromJust()); } // ES6 section 19.1.2.12 Object.isFrozen ( O ) BUILTIN(ObjectIsFrozen) { HandleScope scope(isolate); Handle
object = args.atOrUndefined(isolate, 1); Maybe
result = object->IsJSReceiver() ? JSReceiver::TestIntegrityLevel( Handle
::cast(object), FROZEN) : Just(true); MAYBE_RETURN(result, isolate->heap()->exception()); return isolate->heap()->ToBoolean(result.FromJust()); } // ES6 section 19.1.2.13 Object.isSealed ( O ) BUILTIN(ObjectIsSealed) { HandleScope scope(isolate); Handle
object = args.atOrUndefined(isolate, 1); Maybe
result = object->IsJSReceiver() ? JSReceiver::TestIntegrityLevel( Handle
::cast(object), SEALED) : Just(true); MAYBE_RETURN(result, isolate->heap()->exception()); return isolate->heap()->ToBoolean(result.FromJust()); } // ES6 section 19.1.2.14 Object.keys ( O ) BUILTIN(ObjectKeys) { HandleScope scope(isolate); Handle
object = args.atOrUndefined(isolate, 1); Handle
receiver; ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, Execution::ToObject(isolate, object)); Handle
keys; int enum_length = receiver->map()->EnumLength(); if (enum_length != kInvalidEnumCacheSentinel && JSObject::cast(*receiver)->elements() == isolate->heap()->empty_fixed_array()) { DCHECK(receiver->IsJSObject()); DCHECK(!JSObject::cast(*receiver)->HasNamedInterceptor()); DCHECK(!JSObject::cast(*receiver)->IsAccessCheckNeeded()); DCHECK(!HeapObject::cast(receiver->map()->prototype()) ->map() ->is_hidden_prototype()); DCHECK(JSObject::cast(*receiver)->HasFastProperties()); if (enum_length == 0) { keys = isolate->factory()->empty_fixed_array(); } else { Handle
cache( receiver->map()->instance_descriptors()->GetEnumCache()); keys = isolate->factory()->NewFixedArray(enum_length); for (int i = 0; i < enum_length; i++) { keys->set(i, cache->get(i)); } } } else { ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, keys, JSReceiver::GetKeys(receiver, JSReceiver::OWN_ONLY, ENUMERABLE_STRINGS, CONVERT_TO_STRING)); } return *isolate->factory()->NewJSArrayWithElements(keys, FAST_ELEMENTS); } // ES6 section 19.1.2.15 Object.preventExtensions ( O ) BUILTIN(ObjectPreventExtensions) { HandleScope scope(isolate); Handle
object = args.atOrUndefined(isolate, 1); if (object->IsJSReceiver()) { MAYBE_RETURN(JSReceiver::PreventExtensions(Handle
::cast(object), Object::THROW_ON_ERROR), isolate->heap()->exception()); } return *object; } // ES6 section 19.1.2.17 Object.seal ( O ) BUILTIN(ObjectSeal) { HandleScope scope(isolate); Handle
object = args.atOrUndefined(isolate, 1); if (object->IsJSReceiver()) { MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle
::cast(object), SEALED, Object::THROW_ON_ERROR), isolate->heap()->exception()); } return *object; } namespace { bool CodeGenerationFromStringsAllowed(Isolate* isolate, Handle
context) { DCHECK(context->allow_code_gen_from_strings()->IsFalse()); // Check with callback if set. AllowCodeGenerationFromStringsCallback callback = isolate->allow_code_gen_callback(); if (callback == NULL) { // No callback set and code generation disallowed. return false; } else { // Callback set. Let it decide if code generation is allowed. VMState
state(isolate); return callback(v8::Utils::ToLocal(context)); } } MaybeHandle
CompileString(Handle