// Copyright 2017 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/builtins-array-gen.h" #include "src/builtins/builtins-iterator-gen.h" #include "src/builtins/builtins-string-gen.h" #include "src/builtins/builtins-typed-array-gen.h" #include "src/builtins/builtins-utils-gen.h" #include "src/builtins/builtins.h" #include "src/codegen/code-stub-assembler.h" #include "src/execution/frame-constants.h" #include "src/heap/factory-inl.h" #include "src/objects/allocation-site-inl.h" #include "src/objects/arguments-inl.h" #include "src/objects/property-cell.h" namespace v8 { namespace internal { using Node = compiler::Node; using IteratorRecord = TorqueStructIteratorRecord; ArrayBuiltinsAssembler::ArrayBuiltinsAssembler( compiler::CodeAssemblerState* state) : CodeStubAssembler(state), k_(this, MachineRepresentation::kTagged), a_(this, MachineRepresentation::kTagged), to_(this, MachineRepresentation::kTagged, SmiConstant(0)), fully_spec_compliant_(this, {&k_, &a_, &to_}) {} void ArrayBuiltinsAssembler::TypedArrayMapResultGenerator() { // 6. Let A be ? TypedArraySpeciesCreate(O, len). TNode original_array = CAST(o()); TNode length = CAST(len_); const char* method_name = "%TypedArray%.prototype.map"; TNode a = TypedArraySpeciesCreateByLength( context(), method_name, original_array, length); // In the Spec and our current implementation, the length check is already // performed in TypedArraySpeciesCreate. CSA_ASSERT(this, UintPtrLessThanOrEqual(SmiUntag(CAST(len_)), LoadJSTypedArrayLength(a))); fast_typed_array_target_ = Word32Equal(LoadElementsKind(original_array), LoadElementsKind(a)); a_.Bind(a); } // See tc39.github.io/ecma262/#sec-%typedarray%.prototype.map. Node* ArrayBuiltinsAssembler::TypedArrayMapProcessor(Node* k_value, Node* k) { // 8. c. Let mapped_value be ? Call(callbackfn, T, « kValue, k, O »). Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(), k_value, k, o()); Label fast(this), slow(this), done(this), detached(this, Label::kDeferred); // 8. d. Perform ? Set(A, Pk, mapped_value, true). // Since we know that A is a TypedArray, this always ends up in // #sec-integer-indexed-exotic-objects-set-p-v-receiver and then // tc39.github.io/ecma262/#sec-integerindexedelementset . Branch(fast_typed_array_target_, &fast, &slow); BIND(&fast); // #sec-integerindexedelementset // 5. If arrayTypeName is "BigUint64Array" or "BigInt64Array", let // numValue be ? ToBigInt(v). // 6. Otherwise, let numValue be ? ToNumber(value). Node* num_value; if (source_elements_kind_ == BIGINT64_ELEMENTS || source_elements_kind_ == BIGUINT64_ELEMENTS) { num_value = ToBigInt(context(), mapped_value); } else { num_value = ToNumber_Inline(context(), mapped_value); } // The only way how this can bailout is because of a detached buffer. EmitElementStore(a(), k, num_value, source_elements_kind_, KeyedAccessStoreMode::STANDARD_STORE, &detached, context()); Goto(&done); BIND(&slow); SetPropertyStrict(context(), CAST(a()), CAST(k), CAST(mapped_value)); Goto(&done); BIND(&detached); // tc39.github.io/ecma262/#sec-integerindexedelementset // 8. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. ThrowTypeError(context_, MessageTemplate::kDetachedOperation, name_); BIND(&done); return a(); } void ArrayBuiltinsAssembler::NullPostLoopAction() {} void ArrayBuiltinsAssembler::FillFixedArrayWithSmiZero(TNode array, TNode smi_length) { CSA_ASSERT(this, Word32BinaryNot(IsFixedDoubleArray(array))); TNode length = SmiToIntPtr(smi_length); TNode byte_length = TimesTaggedSize(length); CSA_ASSERT(this, UintPtrLessThan(length, byte_length)); static const int32_t fa_base_data_offset = FixedArray::kHeaderSize - kHeapObjectTag; TNode backing_store = IntPtrAdd(BitcastTaggedToWord(array), IntPtrConstant(fa_base_data_offset)); // Call out to memset to perform initialization. TNode memset = ExternalConstant(ExternalReference::libc_memset_function()); STATIC_ASSERT(kSizetSize == kIntptrSize); CallCFunction(memset, MachineType::Pointer(), std::make_pair(MachineType::Pointer(), backing_store), std::make_pair(MachineType::IntPtr(), IntPtrConstant(0)), std::make_pair(MachineType::UintPtr(), byte_length)); } void ArrayBuiltinsAssembler::ReturnFromBuiltin(Node* value) { if (argc_ == nullptr) { Return(value); } else { // argc_ doesn't include the receiver, so it has to be added back in // manually. PopAndReturn(IntPtrAdd(argc_, IntPtrConstant(1)), value); } } void ArrayBuiltinsAssembler::InitIteratingArrayBuiltinBody( TNode context, TNode receiver, Node* callbackfn, Node* this_arg, TNode argc) { context_ = context; receiver_ = receiver; callbackfn_ = callbackfn; this_arg_ = this_arg; argc_ = argc; } void ArrayBuiltinsAssembler::GenerateIteratingTypedArrayBuiltinBody( const char* name, const BuiltinResultGenerator& generator, const CallResultProcessor& processor, const PostLoopAction& action, ForEachDirection direction) { name_ = name; // ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray Label throw_not_typed_array(this, Label::kDeferred); GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array); TNode typed_array_map = LoadMap(CAST(receiver_)); GotoIfNot(IsJSTypedArrayMap(typed_array_map), &throw_not_typed_array); TNode typed_array = CAST(receiver_); o_ = typed_array; TNode array_buffer = LoadJSArrayBufferViewBuffer(typed_array); ThrowIfArrayBufferIsDetached(context_, array_buffer, name_); len_ = ChangeUintPtrToTagged(LoadJSTypedArrayLength(typed_array)); Label throw_not_callable(this, Label::kDeferred); Label distinguish_types(this); GotoIf(TaggedIsSmi(callbackfn_), &throw_not_callable); Branch(IsCallableMap(LoadMap(callbackfn_)), &distinguish_types, &throw_not_callable); BIND(&throw_not_typed_array); ThrowTypeError(context_, MessageTemplate::kNotTypedArray); BIND(&throw_not_callable); ThrowTypeError(context_, MessageTemplate::kCalledNonCallable, callbackfn_); Label unexpected_instance_type(this); BIND(&unexpected_instance_type); Unreachable(); std::vector elements_kinds = { #define ELEMENTS_KIND(Type, type, TYPE, ctype) TYPE##_ELEMENTS, TYPED_ARRAYS(ELEMENTS_KIND) #undef ELEMENTS_KIND }; std::list