11cb0ef41Sopenharmony_ci// Copyright 2016 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/builtins/builtins-utils-inl.h" 61cb0ef41Sopenharmony_ci#include "src/builtins/builtins.h" 71cb0ef41Sopenharmony_ci#include "src/handles/maybe-handles-inl.h" 81cb0ef41Sopenharmony_ci#include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop. 91cb0ef41Sopenharmony_ci#include "src/logging/counters.h" 101cb0ef41Sopenharmony_ci#include "src/numbers/conversions.h" 111cb0ef41Sopenharmony_ci#include "src/objects/js-array-buffer-inl.h" 121cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_cinamespace v8 { 151cb0ef41Sopenharmony_cinamespace internal { 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ci#define CHECK_SHARED(expected, name, method) \ 181cb0ef41Sopenharmony_ci if (name->is_shared() != expected) { \ 191cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( \ 201cb0ef41Sopenharmony_ci isolate, \ 211cb0ef41Sopenharmony_ci NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, \ 221cb0ef41Sopenharmony_ci isolate->factory()->NewStringFromAsciiChecked(method), \ 231cb0ef41Sopenharmony_ci name)); \ 241cb0ef41Sopenharmony_ci } 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci#define CHECK_RESIZABLE(expected, name, method) \ 271cb0ef41Sopenharmony_ci if (name->is_resizable() != expected) { \ 281cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( \ 291cb0ef41Sopenharmony_ci isolate, \ 301cb0ef41Sopenharmony_ci NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, \ 311cb0ef41Sopenharmony_ci isolate->factory()->NewStringFromAsciiChecked(method), \ 321cb0ef41Sopenharmony_ci name)); \ 331cb0ef41Sopenharmony_ci } 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci// ----------------------------------------------------------------------------- 361cb0ef41Sopenharmony_ci// ES#sec-arraybuffer-objects 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_cinamespace { 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ciObject ConstructBuffer(Isolate* isolate, Handle<JSFunction> target, 411cb0ef41Sopenharmony_ci Handle<JSReceiver> new_target, Handle<Object> length, 421cb0ef41Sopenharmony_ci Handle<Object> max_length, InitializedFlag initialized) { 431cb0ef41Sopenharmony_ci SharedFlag shared = *target != target->native_context().array_buffer_fun() 441cb0ef41Sopenharmony_ci ? SharedFlag::kShared 451cb0ef41Sopenharmony_ci : SharedFlag::kNotShared; 461cb0ef41Sopenharmony_ci ResizableFlag resizable = max_length.is_null() ? ResizableFlag::kNotResizable 471cb0ef41Sopenharmony_ci : ResizableFlag::kResizable; 481cb0ef41Sopenharmony_ci Handle<JSObject> result; 491cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 501cb0ef41Sopenharmony_ci isolate, result, 511cb0ef41Sopenharmony_ci JSObject::New(target, new_target, Handle<AllocationSite>::null())); 521cb0ef41Sopenharmony_ci auto array_buffer = Handle<JSArrayBuffer>::cast(result); 531cb0ef41Sopenharmony_ci // Ensure that all fields are initialized because BackingStore::Allocate is 541cb0ef41Sopenharmony_ci // allowed to GC. Note that we cannot move the allocation of the ArrayBuffer 551cb0ef41Sopenharmony_ci // after BackingStore::Allocate because of the spec. 561cb0ef41Sopenharmony_ci array_buffer->Setup(shared, resizable, nullptr); 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci size_t byte_length; 591cb0ef41Sopenharmony_ci size_t max_byte_length = 0; 601cb0ef41Sopenharmony_ci if (!TryNumberToSize(*length, &byte_length) || 611cb0ef41Sopenharmony_ci byte_length > JSArrayBuffer::kMaxByteLength) { 621cb0ef41Sopenharmony_ci // ToNumber failed. 631cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 641cb0ef41Sopenharmony_ci isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength)); 651cb0ef41Sopenharmony_ci } 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci std::unique_ptr<BackingStore> backing_store; 681cb0ef41Sopenharmony_ci if (resizable == ResizableFlag::kNotResizable) { 691cb0ef41Sopenharmony_ci backing_store = 701cb0ef41Sopenharmony_ci BackingStore::Allocate(isolate, byte_length, shared, initialized); 711cb0ef41Sopenharmony_ci max_byte_length = byte_length; 721cb0ef41Sopenharmony_ci } else { 731cb0ef41Sopenharmony_ci if (!TryNumberToSize(*max_length, &max_byte_length)) { 741cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 751cb0ef41Sopenharmony_ci isolate, 761cb0ef41Sopenharmony_ci NewRangeError(MessageTemplate::kInvalidArrayBufferMaxLength)); 771cb0ef41Sopenharmony_ci } 781cb0ef41Sopenharmony_ci if (byte_length > max_byte_length) { 791cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 801cb0ef41Sopenharmony_ci isolate, 811cb0ef41Sopenharmony_ci NewRangeError(MessageTemplate::kInvalidArrayBufferMaxLength)); 821cb0ef41Sopenharmony_ci } 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci size_t page_size, initial_pages, max_pages; 851cb0ef41Sopenharmony_ci MAYBE_RETURN(JSArrayBuffer::GetResizableBackingStorePageConfiguration( 861cb0ef41Sopenharmony_ci isolate, byte_length, max_byte_length, kThrowOnError, 871cb0ef41Sopenharmony_ci &page_size, &initial_pages, &max_pages), 881cb0ef41Sopenharmony_ci ReadOnlyRoots(isolate).exception()); 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ci constexpr bool kIsWasmMemory = false; 911cb0ef41Sopenharmony_ci backing_store = BackingStore::TryAllocateAndPartiallyCommitMemory( 921cb0ef41Sopenharmony_ci isolate, byte_length, max_byte_length, page_size, initial_pages, 931cb0ef41Sopenharmony_ci max_pages, kIsWasmMemory, shared); 941cb0ef41Sopenharmony_ci } 951cb0ef41Sopenharmony_ci if (!backing_store) { 961cb0ef41Sopenharmony_ci // Allocation of backing store failed. 971cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 981cb0ef41Sopenharmony_ci isolate, NewRangeError(MessageTemplate::kArrayBufferAllocationFailed)); 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci array_buffer->Attach(std::move(backing_store)); 1021cb0ef41Sopenharmony_ci array_buffer->set_max_byte_length(max_byte_length); 1031cb0ef41Sopenharmony_ci return *array_buffer; 1041cb0ef41Sopenharmony_ci} 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci} // namespace 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci// ES #sec-arraybuffer-constructor 1091cb0ef41Sopenharmony_ciBUILTIN(ArrayBufferConstructor) { 1101cb0ef41Sopenharmony_ci HandleScope scope(isolate); 1111cb0ef41Sopenharmony_ci Handle<JSFunction> target = args.target(); 1121cb0ef41Sopenharmony_ci DCHECK(*target == target->native_context().array_buffer_fun() || 1131cb0ef41Sopenharmony_ci *target == target->native_context().shared_array_buffer_fun()); 1141cb0ef41Sopenharmony_ci if (args.new_target()->IsUndefined(isolate)) { // [[Call]] 1151cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 1161cb0ef41Sopenharmony_ci isolate, NewTypeError(MessageTemplate::kConstructorNotFunction, 1171cb0ef41Sopenharmony_ci handle(target->shared().Name(), isolate))); 1181cb0ef41Sopenharmony_ci } 1191cb0ef41Sopenharmony_ci // [[Construct]] 1201cb0ef41Sopenharmony_ci Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target()); 1211cb0ef41Sopenharmony_ci Handle<Object> length = args.atOrUndefined(isolate, 1); 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ci Handle<Object> number_length; 1241cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_length, 1251cb0ef41Sopenharmony_ci Object::ToInteger(isolate, length)); 1261cb0ef41Sopenharmony_ci if (number_length->Number() < 0.0) { 1271cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 1281cb0ef41Sopenharmony_ci isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength)); 1291cb0ef41Sopenharmony_ci } 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci Handle<Object> number_max_length; 1321cb0ef41Sopenharmony_ci if (FLAG_harmony_rab_gsab) { 1331cb0ef41Sopenharmony_ci Handle<Object> max_length; 1341cb0ef41Sopenharmony_ci Handle<Object> options = args.atOrUndefined(isolate, 2); 1351cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1361cb0ef41Sopenharmony_ci isolate, max_length, 1371cb0ef41Sopenharmony_ci JSObject::ReadFromOptionsBag( 1381cb0ef41Sopenharmony_ci options, isolate->factory()->max_byte_length_string(), isolate)); 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci if (!max_length->IsUndefined(isolate)) { 1411cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1421cb0ef41Sopenharmony_ci isolate, number_max_length, Object::ToInteger(isolate, max_length)); 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci } 1451cb0ef41Sopenharmony_ci return ConstructBuffer(isolate, target, new_target, number_length, 1461cb0ef41Sopenharmony_ci number_max_length, InitializedFlag::kZeroInitialized); 1471cb0ef41Sopenharmony_ci} 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci// This is a helper to construct an ArrayBuffer with uinitialized memory. 1501cb0ef41Sopenharmony_ci// This means the caller must ensure the buffer is totally initialized in 1511cb0ef41Sopenharmony_ci// all cases, or we will expose uinitialized memory to user code. 1521cb0ef41Sopenharmony_ciBUILTIN(ArrayBufferConstructor_DoNotInitialize) { 1531cb0ef41Sopenharmony_ci HandleScope scope(isolate); 1541cb0ef41Sopenharmony_ci Handle<JSFunction> target(isolate->native_context()->array_buffer_fun(), 1551cb0ef41Sopenharmony_ci isolate); 1561cb0ef41Sopenharmony_ci Handle<Object> length = args.atOrUndefined(isolate, 1); 1571cb0ef41Sopenharmony_ci return ConstructBuffer(isolate, target, target, length, Handle<Object>(), 1581cb0ef41Sopenharmony_ci InitializedFlag::kUninitialized); 1591cb0ef41Sopenharmony_ci} 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_cistatic Object SliceHelper(BuiltinArguments args, Isolate* isolate, 1621cb0ef41Sopenharmony_ci const char* kMethodName, bool is_shared) { 1631cb0ef41Sopenharmony_ci HandleScope scope(isolate); 1641cb0ef41Sopenharmony_ci Handle<Object> start = args.at(1); 1651cb0ef41Sopenharmony_ci Handle<Object> end = args.atOrUndefined(isolate, 2); 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci // * If Type(O) is not Object, throw a TypeError exception. 1681cb0ef41Sopenharmony_ci // * If O does not have an [[ArrayBufferData]] internal slot, throw a 1691cb0ef41Sopenharmony_ci // TypeError exception. 1701cb0ef41Sopenharmony_ci CHECK_RECEIVER(JSArrayBuffer, array_buffer, kMethodName); 1711cb0ef41Sopenharmony_ci // * [AB] If IsSharedArrayBuffer(O) is true, throw a TypeError exception. 1721cb0ef41Sopenharmony_ci // * [SAB] If IsSharedArrayBuffer(O) is false, throw a TypeError exception. 1731cb0ef41Sopenharmony_ci CHECK_SHARED(is_shared, array_buffer, kMethodName); 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci // * [AB] If IsDetachedBuffer(buffer) is true, throw a TypeError exception. 1761cb0ef41Sopenharmony_ci if (!is_shared && array_buffer->was_detached()) { 1771cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 1781cb0ef41Sopenharmony_ci isolate, NewTypeError(MessageTemplate::kDetachedOperation, 1791cb0ef41Sopenharmony_ci isolate->factory()->NewStringFromAsciiChecked( 1801cb0ef41Sopenharmony_ci kMethodName))); 1811cb0ef41Sopenharmony_ci } 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ci // * [AB] Let len be O.[[ArrayBufferByteLength]]. 1841cb0ef41Sopenharmony_ci // * [SAB] Let len be O.[[ArrayBufferByteLength]]. 1851cb0ef41Sopenharmony_ci double const len = array_buffer->GetByteLength(); 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci // * Let relativeStart be ? ToInteger(start). 1881cb0ef41Sopenharmony_ci Handle<Object> relative_start; 1891cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, relative_start, 1901cb0ef41Sopenharmony_ci Object::ToInteger(isolate, start)); 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci // * If relativeStart < 0, let first be max((len + relativeStart), 0); else 1931cb0ef41Sopenharmony_ci // let first be min(relativeStart, len). 1941cb0ef41Sopenharmony_ci double const first = (relative_start->Number() < 0) 1951cb0ef41Sopenharmony_ci ? std::max(len + relative_start->Number(), 0.0) 1961cb0ef41Sopenharmony_ci : std::min(relative_start->Number(), len); 1971cb0ef41Sopenharmony_ci 1981cb0ef41Sopenharmony_ci // * If end is undefined, let relativeEnd be len; else let relativeEnd be ? 1991cb0ef41Sopenharmony_ci // ToInteger(end). 2001cb0ef41Sopenharmony_ci double relative_end; 2011cb0ef41Sopenharmony_ci if (end->IsUndefined(isolate)) { 2021cb0ef41Sopenharmony_ci relative_end = len; 2031cb0ef41Sopenharmony_ci } else { 2041cb0ef41Sopenharmony_ci Handle<Object> relative_end_obj; 2051cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, relative_end_obj, 2061cb0ef41Sopenharmony_ci Object::ToInteger(isolate, end)); 2071cb0ef41Sopenharmony_ci relative_end = relative_end_obj->Number(); 2081cb0ef41Sopenharmony_ci } 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ci // * If relativeEnd < 0, let final be max((len + relativeEnd), 0); else let 2111cb0ef41Sopenharmony_ci // final be min(relativeEnd, len). 2121cb0ef41Sopenharmony_ci double const final_ = (relative_end < 0) ? std::max(len + relative_end, 0.0) 2131cb0ef41Sopenharmony_ci : std::min(relative_end, len); 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci // * Let newLen be max(final-first, 0). 2161cb0ef41Sopenharmony_ci double const new_len = std::max(final_ - first, 0.0); 2171cb0ef41Sopenharmony_ci Handle<Object> new_len_obj = isolate->factory()->NewNumber(new_len); 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci // * [AB] Let ctor be ? SpeciesConstructor(O, %ArrayBuffer%). 2201cb0ef41Sopenharmony_ci // * [SAB] Let ctor be ? SpeciesConstructor(O, %SharedArrayBuffer%). 2211cb0ef41Sopenharmony_ci Handle<JSFunction> constructor_fun = is_shared 2221cb0ef41Sopenharmony_ci ? isolate->shared_array_buffer_fun() 2231cb0ef41Sopenharmony_ci : isolate->array_buffer_fun(); 2241cb0ef41Sopenharmony_ci Handle<Object> ctor; 2251cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2261cb0ef41Sopenharmony_ci isolate, ctor, 2271cb0ef41Sopenharmony_ci Object::SpeciesConstructor( 2281cb0ef41Sopenharmony_ci isolate, Handle<JSReceiver>::cast(args.receiver()), constructor_fun)); 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_ci // * Let new be ? Construct(ctor, newLen). 2311cb0ef41Sopenharmony_ci Handle<JSReceiver> new_; 2321cb0ef41Sopenharmony_ci { 2331cb0ef41Sopenharmony_ci const int argc = 1; 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ci base::ScopedVector<Handle<Object>> argv(argc); 2361cb0ef41Sopenharmony_ci argv[0] = new_len_obj; 2371cb0ef41Sopenharmony_ci 2381cb0ef41Sopenharmony_ci Handle<Object> new_obj; 2391cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2401cb0ef41Sopenharmony_ci isolate, new_obj, Execution::New(isolate, ctor, argc, argv.begin())); 2411cb0ef41Sopenharmony_ci 2421cb0ef41Sopenharmony_ci new_ = Handle<JSReceiver>::cast(new_obj); 2431cb0ef41Sopenharmony_ci } 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci // * If new does not have an [[ArrayBufferData]] internal slot, throw a 2461cb0ef41Sopenharmony_ci // TypeError exception. 2471cb0ef41Sopenharmony_ci if (!new_->IsJSArrayBuffer()) { 2481cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 2491cb0ef41Sopenharmony_ci isolate, 2501cb0ef41Sopenharmony_ci NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, 2511cb0ef41Sopenharmony_ci isolate->factory()->NewStringFromAsciiChecked(kMethodName), 2521cb0ef41Sopenharmony_ci new_)); 2531cb0ef41Sopenharmony_ci } 2541cb0ef41Sopenharmony_ci 2551cb0ef41Sopenharmony_ci // * [AB] If IsSharedArrayBuffer(new) is true, throw a TypeError exception. 2561cb0ef41Sopenharmony_ci // * [SAB] If IsSharedArrayBuffer(new) is false, throw a TypeError exception. 2571cb0ef41Sopenharmony_ci Handle<JSArrayBuffer> new_array_buffer = Handle<JSArrayBuffer>::cast(new_); 2581cb0ef41Sopenharmony_ci CHECK_SHARED(is_shared, new_array_buffer, kMethodName); 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_ci // The created ArrayBuffer might or might not be resizable, since the species 2611cb0ef41Sopenharmony_ci // constructor might return a non-resizable or a resizable buffer. 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_ci // * [AB] If IsDetachedBuffer(new) is true, throw a TypeError exception. 2641cb0ef41Sopenharmony_ci if (!is_shared && new_array_buffer->was_detached()) { 2651cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 2661cb0ef41Sopenharmony_ci isolate, NewTypeError(MessageTemplate::kDetachedOperation, 2671cb0ef41Sopenharmony_ci isolate->factory()->NewStringFromAsciiChecked( 2681cb0ef41Sopenharmony_ci kMethodName))); 2691cb0ef41Sopenharmony_ci } 2701cb0ef41Sopenharmony_ci 2711cb0ef41Sopenharmony_ci // * [AB] If SameValue(new, O) is true, throw a TypeError exception. 2721cb0ef41Sopenharmony_ci if (!is_shared && new_->SameValue(*args.receiver())) { 2731cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 2741cb0ef41Sopenharmony_ci isolate, NewTypeError(MessageTemplate::kArrayBufferSpeciesThis)); 2751cb0ef41Sopenharmony_ci } 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ci // * [SAB] If new.[[ArrayBufferData]] and O.[[ArrayBufferData]] are the same 2781cb0ef41Sopenharmony_ci // Shared Data Block values, throw a TypeError exception. 2791cb0ef41Sopenharmony_ci if (is_shared && 2801cb0ef41Sopenharmony_ci new_array_buffer->backing_store() == array_buffer->backing_store()) { 2811cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 2821cb0ef41Sopenharmony_ci isolate, NewTypeError(MessageTemplate::kSharedArrayBufferSpeciesThis)); 2831cb0ef41Sopenharmony_ci } 2841cb0ef41Sopenharmony_ci 2851cb0ef41Sopenharmony_ci // * If new.[[ArrayBufferByteLength]] < newLen, throw a TypeError exception. 2861cb0ef41Sopenharmony_ci size_t new_array_buffer_byte_length = new_array_buffer->GetByteLength(); 2871cb0ef41Sopenharmony_ci if (new_array_buffer_byte_length < new_len) { 2881cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 2891cb0ef41Sopenharmony_ci isolate, 2901cb0ef41Sopenharmony_ci NewTypeError(is_shared ? MessageTemplate::kSharedArrayBufferTooShort 2911cb0ef41Sopenharmony_ci : MessageTemplate::kArrayBufferTooShort)); 2921cb0ef41Sopenharmony_ci } 2931cb0ef41Sopenharmony_ci 2941cb0ef41Sopenharmony_ci // * [AB] NOTE: Side-effects of the above steps may have detached O. 2951cb0ef41Sopenharmony_ci // * [AB] If IsDetachedBuffer(O) is true, throw a TypeError exception. 2961cb0ef41Sopenharmony_ci if (!is_shared && array_buffer->was_detached()) { 2971cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 2981cb0ef41Sopenharmony_ci isolate, NewTypeError(MessageTemplate::kDetachedOperation, 2991cb0ef41Sopenharmony_ci isolate->factory()->NewStringFromAsciiChecked( 3001cb0ef41Sopenharmony_ci kMethodName))); 3011cb0ef41Sopenharmony_ci } 3021cb0ef41Sopenharmony_ci 3031cb0ef41Sopenharmony_ci // * Let fromBuf be O.[[ArrayBufferData]]. 3041cb0ef41Sopenharmony_ci // * Let toBuf be new.[[ArrayBufferData]]. 3051cb0ef41Sopenharmony_ci // * Perform CopyDataBlockBytes(toBuf, 0, fromBuf, first, newLen). 3061cb0ef41Sopenharmony_ci size_t first_size = first; 3071cb0ef41Sopenharmony_ci size_t new_len_size = new_len; 3081cb0ef41Sopenharmony_ci DCHECK(new_array_buffer_byte_length >= new_len_size); 3091cb0ef41Sopenharmony_ci 3101cb0ef41Sopenharmony_ci if (new_len_size != 0) { 3111cb0ef41Sopenharmony_ci size_t from_byte_length = array_buffer->GetByteLength(); 3121cb0ef41Sopenharmony_ci if (V8_UNLIKELY(!is_shared && array_buffer->is_resizable())) { 3131cb0ef41Sopenharmony_ci // The above steps might have resized the underlying buffer. In that case, 3141cb0ef41Sopenharmony_ci // only copy the still-accessible portion of the underlying data. 3151cb0ef41Sopenharmony_ci if (first_size > from_byte_length) { 3161cb0ef41Sopenharmony_ci return *new_; // Nothing to copy. 3171cb0ef41Sopenharmony_ci } 3181cb0ef41Sopenharmony_ci if (new_len_size > from_byte_length - first_size) { 3191cb0ef41Sopenharmony_ci new_len_size = from_byte_length - first_size; 3201cb0ef41Sopenharmony_ci } 3211cb0ef41Sopenharmony_ci } 3221cb0ef41Sopenharmony_ci DCHECK(first_size <= from_byte_length); 3231cb0ef41Sopenharmony_ci DCHECK(from_byte_length - first_size >= new_len_size); 3241cb0ef41Sopenharmony_ci uint8_t* from_data = 3251cb0ef41Sopenharmony_ci reinterpret_cast<uint8_t*>(array_buffer->backing_store()) + first_size; 3261cb0ef41Sopenharmony_ci uint8_t* to_data = 3271cb0ef41Sopenharmony_ci reinterpret_cast<uint8_t*>(new_array_buffer->backing_store()); 3281cb0ef41Sopenharmony_ci if (is_shared) { 3291cb0ef41Sopenharmony_ci base::Relaxed_Memcpy(reinterpret_cast<base::Atomic8*>(to_data), 3301cb0ef41Sopenharmony_ci reinterpret_cast<base::Atomic8*>(from_data), 3311cb0ef41Sopenharmony_ci new_len_size); 3321cb0ef41Sopenharmony_ci } else { 3331cb0ef41Sopenharmony_ci CopyBytes(to_data, from_data, new_len_size); 3341cb0ef41Sopenharmony_ci } 3351cb0ef41Sopenharmony_ci } 3361cb0ef41Sopenharmony_ci 3371cb0ef41Sopenharmony_ci return *new_; 3381cb0ef41Sopenharmony_ci} 3391cb0ef41Sopenharmony_ci 3401cb0ef41Sopenharmony_ci// ES #sec-sharedarraybuffer.prototype.slice 3411cb0ef41Sopenharmony_ciBUILTIN(SharedArrayBufferPrototypeSlice) { 3421cb0ef41Sopenharmony_ci const char* const kMethodName = "SharedArrayBuffer.prototype.slice"; 3431cb0ef41Sopenharmony_ci return SliceHelper(args, isolate, kMethodName, true); 3441cb0ef41Sopenharmony_ci} 3451cb0ef41Sopenharmony_ci 3461cb0ef41Sopenharmony_ci// ES #sec-arraybuffer.prototype.slice 3471cb0ef41Sopenharmony_ci// ArrayBuffer.prototype.slice ( start, end ) 3481cb0ef41Sopenharmony_ciBUILTIN(ArrayBufferPrototypeSlice) { 3491cb0ef41Sopenharmony_ci const char* const kMethodName = "ArrayBuffer.prototype.slice"; 3501cb0ef41Sopenharmony_ci return SliceHelper(args, isolate, kMethodName, false); 3511cb0ef41Sopenharmony_ci} 3521cb0ef41Sopenharmony_ci 3531cb0ef41Sopenharmony_cistatic Object ResizeHelper(BuiltinArguments args, Isolate* isolate, 3541cb0ef41Sopenharmony_ci const char* kMethodName, bool is_shared) { 3551cb0ef41Sopenharmony_ci HandleScope scope(isolate); 3561cb0ef41Sopenharmony_ci 3571cb0ef41Sopenharmony_ci // 1 Let O be the this value. 3581cb0ef41Sopenharmony_ci // 2. Perform ? RequireInternalSlot(O, [[ArrayBufferMaxByteLength]]). 3591cb0ef41Sopenharmony_ci CHECK_RECEIVER(JSArrayBuffer, array_buffer, kMethodName); 3601cb0ef41Sopenharmony_ci CHECK_RESIZABLE(true, array_buffer, kMethodName); 3611cb0ef41Sopenharmony_ci 3621cb0ef41Sopenharmony_ci // [RAB] 3. If IsSharedArrayBuffer(O) is true, throw a *TypeError* exception 3631cb0ef41Sopenharmony_ci // [GSAB] 3. If IsSharedArrayBuffer(O) is false, throw a *TypeError* exception 3641cb0ef41Sopenharmony_ci CHECK_SHARED(is_shared, array_buffer, kMethodName); 3651cb0ef41Sopenharmony_ci 3661cb0ef41Sopenharmony_ci // Let newByteLength to ? ToIntegerOrInfinity(newLength). 3671cb0ef41Sopenharmony_ci Handle<Object> new_length = args.at(1); 3681cb0ef41Sopenharmony_ci Handle<Object> number_new_byte_length; 3691cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_new_byte_length, 3701cb0ef41Sopenharmony_ci Object::ToInteger(isolate, new_length)); 3711cb0ef41Sopenharmony_ci 3721cb0ef41Sopenharmony_ci // [RAB] If IsDetachedBuffer(O) is true, throw a TypeError exception. 3731cb0ef41Sopenharmony_ci if (!is_shared && array_buffer->was_detached()) { 3741cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 3751cb0ef41Sopenharmony_ci isolate, NewTypeError(MessageTemplate::kDetachedOperation, 3761cb0ef41Sopenharmony_ci isolate->factory()->NewStringFromAsciiChecked( 3771cb0ef41Sopenharmony_ci kMethodName))); 3781cb0ef41Sopenharmony_ci } 3791cb0ef41Sopenharmony_ci 3801cb0ef41Sopenharmony_ci // [RAB] If newByteLength < 0 or newByteLength > 3811cb0ef41Sopenharmony_ci // O.[[ArrayBufferMaxByteLength]], throw a RangeError exception. 3821cb0ef41Sopenharmony_ci 3831cb0ef41Sopenharmony_ci // [GSAB] If newByteLength < currentByteLength or newByteLength > 3841cb0ef41Sopenharmony_ci // O.[[ArrayBufferMaxByteLength]], throw a RangeError exception. 3851cb0ef41Sopenharmony_ci size_t new_byte_length; 3861cb0ef41Sopenharmony_ci if (!TryNumberToSize(*number_new_byte_length, &new_byte_length)) { 3871cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 3881cb0ef41Sopenharmony_ci isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferResizeLength, 3891cb0ef41Sopenharmony_ci isolate->factory()->NewStringFromAsciiChecked( 3901cb0ef41Sopenharmony_ci kMethodName))); 3911cb0ef41Sopenharmony_ci } 3921cb0ef41Sopenharmony_ci 3931cb0ef41Sopenharmony_ci if (is_shared && new_byte_length < array_buffer->byte_length()) { 3941cb0ef41Sopenharmony_ci // GrowableSharedArrayBuffer is only allowed to grow. 3951cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 3961cb0ef41Sopenharmony_ci isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferResizeLength, 3971cb0ef41Sopenharmony_ci isolate->factory()->NewStringFromAsciiChecked( 3981cb0ef41Sopenharmony_ci kMethodName))); 3991cb0ef41Sopenharmony_ci } 4001cb0ef41Sopenharmony_ci 4011cb0ef41Sopenharmony_ci if (new_byte_length > array_buffer->max_byte_length()) { 4021cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 4031cb0ef41Sopenharmony_ci isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferResizeLength, 4041cb0ef41Sopenharmony_ci isolate->factory()->NewStringFromAsciiChecked( 4051cb0ef41Sopenharmony_ci kMethodName))); 4061cb0ef41Sopenharmony_ci } 4071cb0ef41Sopenharmony_ci 4081cb0ef41Sopenharmony_ci size_t page_size = AllocatePageSize(); 4091cb0ef41Sopenharmony_ci size_t new_committed_pages; 4101cb0ef41Sopenharmony_ci bool round_return_value = 4111cb0ef41Sopenharmony_ci RoundUpToPageSize(new_byte_length, page_size, 4121cb0ef41Sopenharmony_ci JSArrayBuffer::kMaxByteLength, &new_committed_pages); 4131cb0ef41Sopenharmony_ci CHECK(round_return_value); 4141cb0ef41Sopenharmony_ci 4151cb0ef41Sopenharmony_ci // [RAB] Let hostHandled be ? HostResizeArrayBuffer(O, newByteLength). 4161cb0ef41Sopenharmony_ci // [GSAB] Let hostHandled be ? HostGrowArrayBuffer(O, newByteLength). 4171cb0ef41Sopenharmony_ci // If hostHandled is handled, return undefined. 4181cb0ef41Sopenharmony_ci 4191cb0ef41Sopenharmony_ci // TODO(v8:11111, v8:12746): Wasm integration. 4201cb0ef41Sopenharmony_ci 4211cb0ef41Sopenharmony_ci if (!is_shared) { 4221cb0ef41Sopenharmony_ci // [RAB] Let oldBlock be O.[[ArrayBufferData]]. 4231cb0ef41Sopenharmony_ci // [RAB] Let newBlock be ? CreateByteDataBlock(newByteLength). 4241cb0ef41Sopenharmony_ci // [RAB] Let copyLength be min(newByteLength, O.[[ArrayBufferByteLength]]). 4251cb0ef41Sopenharmony_ci // [RAB] Perform CopyDataBlockBytes(newBlock, 0, oldBlock, 0, copyLength). 4261cb0ef41Sopenharmony_ci // [RAB] NOTE: Neither creation of the new Data Block nor copying from the 4271cb0ef41Sopenharmony_ci // old Data Block are observable. Implementations reserve the right to 4281cb0ef41Sopenharmony_ci // implement this method as in-place growth or shrinkage. 4291cb0ef41Sopenharmony_ci if (array_buffer->GetBackingStore()->ResizeInPlace( 4301cb0ef41Sopenharmony_ci isolate, new_byte_length, new_committed_pages * page_size) != 4311cb0ef41Sopenharmony_ci BackingStore::ResizeOrGrowResult::kSuccess) { 4321cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 4331cb0ef41Sopenharmony_ci isolate, NewRangeError(MessageTemplate::kOutOfMemory, 4341cb0ef41Sopenharmony_ci isolate->factory()->NewStringFromAsciiChecked( 4351cb0ef41Sopenharmony_ci kMethodName))); 4361cb0ef41Sopenharmony_ci } 4371cb0ef41Sopenharmony_ci // [RAB] Set O.[[ArrayBufferByteLength]] to newLength. 4381cb0ef41Sopenharmony_ci array_buffer->set_byte_length(new_byte_length); 4391cb0ef41Sopenharmony_ci } else { 4401cb0ef41Sopenharmony_ci // [GSAB] (Detailed description of the algorithm omitted.) 4411cb0ef41Sopenharmony_ci auto result = array_buffer->GetBackingStore()->GrowInPlace( 4421cb0ef41Sopenharmony_ci isolate, new_byte_length, new_committed_pages * page_size); 4431cb0ef41Sopenharmony_ci if (result == BackingStore::ResizeOrGrowResult::kFailure) { 4441cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 4451cb0ef41Sopenharmony_ci isolate, NewRangeError(MessageTemplate::kOutOfMemory, 4461cb0ef41Sopenharmony_ci isolate->factory()->NewStringFromAsciiChecked( 4471cb0ef41Sopenharmony_ci kMethodName))); 4481cb0ef41Sopenharmony_ci } 4491cb0ef41Sopenharmony_ci if (result == BackingStore::ResizeOrGrowResult::kRace) { 4501cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 4511cb0ef41Sopenharmony_ci isolate, 4521cb0ef41Sopenharmony_ci NewRangeError( 4531cb0ef41Sopenharmony_ci MessageTemplate::kInvalidArrayBufferResizeLength, 4541cb0ef41Sopenharmony_ci isolate->factory()->NewStringFromAsciiChecked(kMethodName))); 4551cb0ef41Sopenharmony_ci } 4561cb0ef41Sopenharmony_ci // Invariant: byte_length for a GSAB is 0 (it needs to be read from the 4571cb0ef41Sopenharmony_ci // BackingStore). 4581cb0ef41Sopenharmony_ci CHECK_EQ(0, array_buffer->byte_length()); 4591cb0ef41Sopenharmony_ci } 4601cb0ef41Sopenharmony_ci return ReadOnlyRoots(isolate).undefined_value(); 4611cb0ef41Sopenharmony_ci} 4621cb0ef41Sopenharmony_ci 4631cb0ef41Sopenharmony_ci// ES #sec-get-sharedarraybuffer.prototype.bytelength 4641cb0ef41Sopenharmony_ci// get SharedArrayBuffer.prototype.byteLength 4651cb0ef41Sopenharmony_ciBUILTIN(SharedArrayBufferPrototypeGetByteLength) { 4661cb0ef41Sopenharmony_ci const char* const kMethodName = "get SharedArrayBuffer.prototype.byteLength"; 4671cb0ef41Sopenharmony_ci HandleScope scope(isolate); 4681cb0ef41Sopenharmony_ci // 1. Let O be the this value. 4691cb0ef41Sopenharmony_ci // 2. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]). 4701cb0ef41Sopenharmony_ci CHECK_RECEIVER(JSArrayBuffer, array_buffer, kMethodName); 4711cb0ef41Sopenharmony_ci // 3. If IsSharedArrayBuffer(O) is false, throw a TypeError exception. 4721cb0ef41Sopenharmony_ci CHECK_SHARED(true, array_buffer, kMethodName); 4731cb0ef41Sopenharmony_ci 4741cb0ef41Sopenharmony_ci DCHECK_EQ(array_buffer->max_byte_length(), 4751cb0ef41Sopenharmony_ci array_buffer->GetBackingStore()->max_byte_length()); 4761cb0ef41Sopenharmony_ci 4771cb0ef41Sopenharmony_ci // 4. Let length be ArrayBufferByteLength(O, SeqCst). 4781cb0ef41Sopenharmony_ci size_t byte_length = array_buffer->GetByteLength(); 4791cb0ef41Sopenharmony_ci // 5. Return F(length). 4801cb0ef41Sopenharmony_ci return *isolate->factory()->NewNumberFromSize(byte_length); 4811cb0ef41Sopenharmony_ci} 4821cb0ef41Sopenharmony_ci 4831cb0ef41Sopenharmony_ci// ES #sec-arraybuffer.prototype.resize 4841cb0ef41Sopenharmony_ci// ArrayBuffer.prototype.resize(new_size)) 4851cb0ef41Sopenharmony_ciBUILTIN(ArrayBufferPrototypeResize) { 4861cb0ef41Sopenharmony_ci const char* const kMethodName = "ArrayBuffer.prototype.resize"; 4871cb0ef41Sopenharmony_ci constexpr bool kIsShared = false; 4881cb0ef41Sopenharmony_ci return ResizeHelper(args, isolate, kMethodName, kIsShared); 4891cb0ef41Sopenharmony_ci} 4901cb0ef41Sopenharmony_ci 4911cb0ef41Sopenharmony_ci// ES #sec-sharedarraybuffer.prototype.grow 4921cb0ef41Sopenharmony_ci// SharedArrayBuffer.prototype.grow(new_size)) 4931cb0ef41Sopenharmony_ciBUILTIN(SharedArrayBufferPrototypeGrow) { 4941cb0ef41Sopenharmony_ci const char* const kMethodName = "SharedArrayBuffer.prototype.grow"; 4951cb0ef41Sopenharmony_ci constexpr bool kIsShared = true; 4961cb0ef41Sopenharmony_ci return ResizeHelper(args, isolate, kMethodName, kIsShared); 4971cb0ef41Sopenharmony_ci} 4981cb0ef41Sopenharmony_ci 4991cb0ef41Sopenharmony_ci} // namespace internal 5001cb0ef41Sopenharmony_ci} // namespace v8 501