diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-12 14:07:37 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-17 10:29:26 +0000 |
commit | ec02ee4181c49b61fce1c8fb99292dbb8139cc90 (patch) | |
tree | 25cde714b2b71eb639d1cd53f5a22e9ba76e14ef /chromium/v8/src/runtime | |
parent | bb09965444b5bb20b096a291445170876225268d (diff) | |
download | qtwebengine-chromium-ec02ee4181c49b61fce1c8fb99292dbb8139cc90.tar.gz |
BASELINE: Update Chromium to 59.0.3071.134
Change-Id: Id02ef6fb2204c5fd21668a1c3e6911c83b17585a
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/v8/src/runtime')
21 files changed, 1001 insertions, 1200 deletions
diff --git a/chromium/v8/src/runtime/runtime-array.cc b/chromium/v8/src/runtime/runtime-array.cc index 07c6ad01168..97432b6ef19 100644 --- a/chromium/v8/src/runtime/runtime-array.cc +++ b/chromium/v8/src/runtime/runtime-array.cc @@ -17,20 +17,6 @@ namespace v8 { namespace internal { -RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) { - HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0); - Object* length = prototype->length(); - CHECK(length->IsSmi()); - CHECK(Smi::cast(length)->value() == 0); - CHECK(prototype->HasFastSmiOrObjectElements()); - // This is necessary to enable fast checks for absence of elements - // on Array.prototype and below. - prototype->set_elements(isolate->heap()->empty_fixed_array()); - return Smi::kZero; -} - static void InstallCode( Isolate* isolate, Handle<JSObject> holder, const char* name, Handle<Code> code, int argc = -1, diff --git a/chromium/v8/src/runtime/runtime-atomics.cc b/chromium/v8/src/runtime/runtime-atomics.cc index ff7ded9b090..62986c66618 100644 --- a/chromium/v8/src/runtime/runtime-atomics.cc +++ b/chromium/v8/src/runtime/runtime-atomics.cc @@ -19,13 +19,14 @@ namespace internal { namespace { -inline bool AtomicIsLockFree(uint32_t size) { - return size == 1 || size == 2 || size == 4; -} - #if V8_CC_GNU template <typename T> +inline T ExchangeSeqCst(T* p, T value) { + return __atomic_exchange_n(p, value, __ATOMIC_SEQ_CST); +} + +template <typename T> inline T CompareExchangeSeqCst(T* p, T oldval, T newval) { (void)__atomic_compare_exchange_n(p, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); @@ -57,24 +58,28 @@ inline T XorSeqCst(T* p, T value) { return __atomic_fetch_xor(p, value, __ATOMIC_SEQ_CST); } -template <typename T> -inline T ExchangeSeqCst(T* p, T value) { - return __atomic_exchange_n(p, value, __ATOMIC_SEQ_CST); -} - #elif V8_CC_MSVC -#define InterlockedCompareExchange32 _InterlockedCompareExchange #define InterlockedExchange32 _InterlockedExchange +#define InterlockedCompareExchange32 _InterlockedCompareExchange +#define InterlockedCompareExchange8 _InterlockedCompareExchange8 #define InterlockedExchangeAdd32 _InterlockedExchangeAdd +#define InterlockedExchangeAdd16 _InterlockedExchangeAdd16 +#define InterlockedExchangeAdd8 _InterlockedExchangeAdd8 #define InterlockedAnd32 _InterlockedAnd #define InterlockedOr32 _InterlockedOr #define InterlockedXor32 _InterlockedXor -#define InterlockedExchangeAdd16 _InterlockedExchangeAdd16 -#define InterlockedCompareExchange8 _InterlockedCompareExchange8 -#define InterlockedExchangeAdd8 _InterlockedExchangeAdd8 #define ATOMIC_OPS(type, suffix, vctype) \ + inline type ExchangeSeqCst(type* p, type value) { \ + return InterlockedExchange##suffix(reinterpret_cast<vctype*>(p), \ + bit_cast<vctype>(value)); \ + } \ + inline type CompareExchangeSeqCst(type* p, type oldval, type newval) { \ + return InterlockedCompareExchange##suffix(reinterpret_cast<vctype*>(p), \ + bit_cast<vctype>(newval), \ + bit_cast<vctype>(oldval)); \ + } \ inline type AddSeqCst(type* p, type value) { \ return InterlockedExchangeAdd##suffix(reinterpret_cast<vctype*>(p), \ bit_cast<vctype>(value)); \ @@ -94,16 +99,6 @@ inline T ExchangeSeqCst(T* p, T value) { inline type XorSeqCst(type* p, type value) { \ return InterlockedXor##suffix(reinterpret_cast<vctype*>(p), \ bit_cast<vctype>(value)); \ - } \ - inline type ExchangeSeqCst(type* p, type value) { \ - return InterlockedExchange##suffix(reinterpret_cast<vctype*>(p), \ - bit_cast<vctype>(value)); \ - } \ - \ - inline type CompareExchangeSeqCst(type* p, type oldval, type newval) { \ - return InterlockedCompareExchange##suffix(reinterpret_cast<vctype*>(p), \ - bit_cast<vctype>(newval), \ - bit_cast<vctype>(oldval)); \ } ATOMIC_OPS(int8_t, 8, char) @@ -116,15 +111,15 @@ ATOMIC_OPS(uint32_t, 32, long) /* NOLINT(runtime/int) */ #undef ATOMIC_OPS_INTEGER #undef ATOMIC_OPS -#undef InterlockedCompareExchange32 #undef InterlockedExchange32 +#undef InterlockedCompareExchange32 +#undef InterlockedCompareExchange8 #undef InterlockedExchangeAdd32 +#undef InterlockedExchangeAdd16 +#undef InterlockedExchangeAdd8 #undef InterlockedAnd32 #undef InterlockedOr32 #undef InterlockedXor32 -#undef InterlockedExchangeAdd16 -#undef InterlockedCompareExchange8 -#undef InterlockedExchangeAdd8 #else @@ -176,16 +171,21 @@ inline Object* ToObject(Isolate* isolate, uint16_t t) { return Smi::FromInt(t); } - inline Object* ToObject(Isolate* isolate, int32_t t) { return *isolate->factory()->NewNumber(t); } - inline Object* ToObject(Isolate* isolate, uint32_t t) { return *isolate->factory()->NewNumber(t); } +template <typename T> +inline Object* DoExchange(Isolate* isolate, void* buffer, size_t index, + Handle<Object> obj) { + T value = FromObject<T>(obj); + T result = ExchangeSeqCst(static_cast<T*>(buffer) + index, value); + return ToObject(isolate, result); +} template <typename T> inline Object* DoCompareExchange(Isolate* isolate, void* buffer, size_t index, @@ -197,7 +197,6 @@ inline Object* DoCompareExchange(Isolate* isolate, void* buffer, size_t index, return ToObject(isolate, result); } - template <typename T> inline Object* DoAdd(Isolate* isolate, void* buffer, size_t index, Handle<Object> obj) { @@ -206,7 +205,6 @@ inline Object* DoAdd(Isolate* isolate, void* buffer, size_t index, return ToObject(isolate, result); } - template <typename T> inline Object* DoSub(Isolate* isolate, void* buffer, size_t index, Handle<Object> obj) { @@ -215,7 +213,6 @@ inline Object* DoSub(Isolate* isolate, void* buffer, size_t index, return ToObject(isolate, result); } - template <typename T> inline Object* DoAnd(Isolate* isolate, void* buffer, size_t index, Handle<Object> obj) { @@ -224,7 +221,6 @@ inline Object* DoAnd(Isolate* isolate, void* buffer, size_t index, return ToObject(isolate, result); } - template <typename T> inline Object* DoOr(Isolate* isolate, void* buffer, size_t index, Handle<Object> obj) { @@ -233,7 +229,6 @@ inline Object* DoOr(Isolate* isolate, void* buffer, size_t index, return ToObject(isolate, result); } - template <typename T> inline Object* DoXor(Isolate* isolate, void* buffer, size_t index, Handle<Object> obj) { @@ -242,75 +237,6 @@ inline Object* DoXor(Isolate* isolate, void* buffer, size_t index, return ToObject(isolate, result); } - -template <typename T> -inline Object* DoExchange(Isolate* isolate, void* buffer, size_t index, - Handle<Object> obj) { - T value = FromObject<T>(obj); - T result = ExchangeSeqCst(static_cast<T*>(buffer) + index, value); - return ToObject(isolate, result); -} - - -// Uint8Clamped functions - -uint8_t ClampToUint8(int32_t value) { - if (value < 0) return 0; - if (value > 255) return 255; - return value; -} - - -inline Object* DoCompareExchangeUint8Clamped(Isolate* isolate, void* buffer, - size_t index, - Handle<Object> oldobj, - Handle<Object> newobj) { - typedef int32_t convert_type; - uint8_t oldval = ClampToUint8(FromObject<convert_type>(oldobj)); - uint8_t newval = ClampToUint8(FromObject<convert_type>(newobj)); - uint8_t result = CompareExchangeSeqCst(static_cast<uint8_t*>(buffer) + index, - oldval, newval); - return ToObject(isolate, result); -} - - -#define DO_UINT8_CLAMPED_OP(name, op) \ - inline Object* Do##name##Uint8Clamped(Isolate* isolate, void* buffer, \ - size_t index, Handle<Object> obj) { \ - typedef int32_t convert_type; \ - uint8_t* p = static_cast<uint8_t*>(buffer) + index; \ - convert_type operand = FromObject<convert_type>(obj); \ - uint8_t expected; \ - uint8_t result; \ - do { \ - expected = *p; \ - result = ClampToUint8(static_cast<convert_type>(expected) op operand); \ - } while (CompareExchangeSeqCst(p, expected, result) != expected); \ - return ToObject(isolate, expected); \ - } - -DO_UINT8_CLAMPED_OP(Add, +) -DO_UINT8_CLAMPED_OP(Sub, -) -DO_UINT8_CLAMPED_OP(And, &) -DO_UINT8_CLAMPED_OP(Or, | ) -DO_UINT8_CLAMPED_OP(Xor, ^) - -#undef DO_UINT8_CLAMPED_OP - - -inline Object* DoExchangeUint8Clamped(Isolate* isolate, void* buffer, - size_t index, Handle<Object> obj) { - typedef int32_t convert_type; - uint8_t* p = static_cast<uint8_t*>(buffer) + index; - uint8_t result = ClampToUint8(FromObject<convert_type>(obj)); - uint8_t expected; - do { - expected = *p; - } while (CompareExchangeSeqCst(p, expected, result) != expected); - return ToObject(isolate, expected); -} - - } // anonymous namespace // Duplicated from objects.h @@ -347,13 +273,12 @@ RUNTIME_FUNCTION(Runtime_ThrowInvalidAtomicAccessIndexError) { isolate, NewRangeError(MessageTemplate::kInvalidAtomicAccessIndex)); } -RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) { +RUNTIME_FUNCTION(Runtime_AtomicsExchange) { HandleScope scope(isolate); - DCHECK_EQ(4, args.length()); + DCHECK_EQ(3, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); CONVERT_SIZE_ARG_CHECKED(index, 1); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(oldobj, 2); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(newobj, 3); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); CHECK(sta->GetBuffer()->is_shared()); CHECK_LT(index, NumberToSize(sta->length())); @@ -363,15 +288,11 @@ RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) { switch (sta->type()) { #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \ case kExternal##Type##Array: \ - return DoCompareExchange<ctype>(isolate, source, index, oldobj, newobj); + return DoExchange<ctype>(isolate, source, index, value); INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE - case kExternalUint8ClampedArray: - return DoCompareExchangeUint8Clamped(isolate, source, index, oldobj, - newobj); - default: break; } @@ -380,13 +301,13 @@ RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) { return isolate->heap()->undefined_value(); } - -RUNTIME_FUNCTION(Runtime_AtomicsAdd) { +RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) { HandleScope scope(isolate); - DCHECK_EQ(3, args.length()); + DCHECK_EQ(4, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); CONVERT_SIZE_ARG_CHECKED(index, 1); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(oldobj, 2); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(newobj, 3); CHECK(sta->GetBuffer()->is_shared()); CHECK_LT(index, NumberToSize(sta->length())); @@ -396,14 +317,11 @@ RUNTIME_FUNCTION(Runtime_AtomicsAdd) { switch (sta->type()) { #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \ case kExternal##Type##Array: \ - return DoAdd<ctype>(isolate, source, index, value); + return DoCompareExchange<ctype>(isolate, source, index, oldobj, newobj); INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE - case kExternalUint8ClampedArray: - return DoAddUint8Clamped(isolate, source, index, value); - default: break; } @@ -412,8 +330,9 @@ RUNTIME_FUNCTION(Runtime_AtomicsAdd) { return isolate->heap()->undefined_value(); } - -RUNTIME_FUNCTION(Runtime_AtomicsSub) { +// ES #sec-atomics.add +// Atomics.add( typedArray, index, value ) +RUNTIME_FUNCTION(Runtime_AtomicsAdd) { HandleScope scope(isolate); DCHECK_EQ(3, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); @@ -428,14 +347,11 @@ RUNTIME_FUNCTION(Runtime_AtomicsSub) { switch (sta->type()) { #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \ case kExternal##Type##Array: \ - return DoSub<ctype>(isolate, source, index, value); + return DoAdd<ctype>(isolate, source, index, value); INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE - case kExternalUint8ClampedArray: - return DoSubUint8Clamped(isolate, source, index, value); - default: break; } @@ -444,8 +360,9 @@ RUNTIME_FUNCTION(Runtime_AtomicsSub) { return isolate->heap()->undefined_value(); } - -RUNTIME_FUNCTION(Runtime_AtomicsAnd) { +// ES #sec-atomics.sub +// Atomics.sub( typedArray, index, value ) +RUNTIME_FUNCTION(Runtime_AtomicsSub) { HandleScope scope(isolate); DCHECK_EQ(3, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); @@ -460,14 +377,11 @@ RUNTIME_FUNCTION(Runtime_AtomicsAnd) { switch (sta->type()) { #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \ case kExternal##Type##Array: \ - return DoAnd<ctype>(isolate, source, index, value); + return DoSub<ctype>(isolate, source, index, value); INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE - case kExternalUint8ClampedArray: - return DoAndUint8Clamped(isolate, source, index, value); - default: break; } @@ -476,8 +390,9 @@ RUNTIME_FUNCTION(Runtime_AtomicsAnd) { return isolate->heap()->undefined_value(); } - -RUNTIME_FUNCTION(Runtime_AtomicsOr) { +// ES #sec-atomics.and +// Atomics.and( typedArray, index, value ) +RUNTIME_FUNCTION(Runtime_AtomicsAnd) { HandleScope scope(isolate); DCHECK_EQ(3, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); @@ -492,14 +407,11 @@ RUNTIME_FUNCTION(Runtime_AtomicsOr) { switch (sta->type()) { #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \ case kExternal##Type##Array: \ - return DoOr<ctype>(isolate, source, index, value); + return DoAnd<ctype>(isolate, source, index, value); INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE - case kExternalUint8ClampedArray: - return DoOrUint8Clamped(isolate, source, index, value); - default: break; } @@ -508,8 +420,9 @@ RUNTIME_FUNCTION(Runtime_AtomicsOr) { return isolate->heap()->undefined_value(); } - -RUNTIME_FUNCTION(Runtime_AtomicsXor) { +// ES #sec-atomics.or +// Atomics.or( typedArray, index, value ) +RUNTIME_FUNCTION(Runtime_AtomicsOr) { HandleScope scope(isolate); DCHECK_EQ(3, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); @@ -524,14 +437,11 @@ RUNTIME_FUNCTION(Runtime_AtomicsXor) { switch (sta->type()) { #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \ case kExternal##Type##Array: \ - return DoXor<ctype>(isolate, source, index, value); + return DoOr<ctype>(isolate, source, index, value); INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE - case kExternalUint8ClampedArray: - return DoXorUint8Clamped(isolate, source, index, value); - default: break; } @@ -540,8 +450,9 @@ RUNTIME_FUNCTION(Runtime_AtomicsXor) { return isolate->heap()->undefined_value(); } - -RUNTIME_FUNCTION(Runtime_AtomicsExchange) { +// ES #sec-atomics.xor +// Atomics.xor( typedArray, index, value ) +RUNTIME_FUNCTION(Runtime_AtomicsXor) { HandleScope scope(isolate); DCHECK_EQ(3, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); @@ -556,14 +467,11 @@ RUNTIME_FUNCTION(Runtime_AtomicsExchange) { switch (sta->type()) { #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \ case kExternal##Type##Array: \ - return DoExchange<ctype>(isolate, source, index, value); + return DoXor<ctype>(isolate, source, index, value); INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE - case kExternalUint8ClampedArray: - return DoExchangeUint8Clamped(isolate, source, index, value); - default: break; } @@ -572,13 +480,5 @@ RUNTIME_FUNCTION(Runtime_AtomicsExchange) { return isolate->heap()->undefined_value(); } - -RUNTIME_FUNCTION(Runtime_AtomicsIsLockFree) { - HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(size, 0); - uint32_t usize = NumberToUint32(*size); - return isolate->heap()->ToBoolean(AtomicIsLockFree(usize)); -} } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/runtime/runtime-classes.cc b/chromium/v8/src/runtime/runtime-classes.cc index 9398586de5f..7dadca5026c 100644 --- a/chromium/v8/src/runtime/runtime-classes.cc +++ b/chromium/v8/src/runtime/runtime-classes.cc @@ -52,6 +52,13 @@ RUNTIME_FUNCTION(Runtime_ThrowSuperAlreadyCalledError) { isolate, NewReferenceError(MessageTemplate::kSuperAlreadyCalled)); } +RUNTIME_FUNCTION(Runtime_ThrowSuperNotCalled) { + HandleScope scope(isolate); + DCHECK_EQ(0, args.length()); + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewReferenceError(MessageTemplate::kSuperNotCalled)); +} + namespace { Object* ThrowNotSuperConstructor(Isolate* isolate, Handle<Object> constructor, diff --git a/chromium/v8/src/runtime/runtime-compiler.cc b/chromium/v8/src/runtime/runtime-compiler.cc index f929d736977..b7151f83c64 100644 --- a/chromium/v8/src/runtime/runtime-compiler.cc +++ b/chromium/v8/src/runtime/runtime-compiler.cc @@ -41,19 +41,6 @@ RUNTIME_FUNCTION(Runtime_CompileLazy) { return function->code(); } -RUNTIME_FUNCTION(Runtime_CompileBaseline) { - HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); - StackLimitCheck check(isolate); - if (check.JsHasOverflowed(1 * KB)) return isolate->StackOverflow(); - if (!Compiler::CompileBaseline(function)) { - return isolate->heap()->exception(); - } - DCHECK(function->is_compiled()); - return function->code(); -} - RUNTIME_FUNCTION(Runtime_CompileOptimized_Concurrent) { HandleScope scope(isolate); DCHECK_EQ(1, args.length()); @@ -213,14 +200,9 @@ RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) { isolate->thread_manager()->IterateArchivedThreads(&activations_finder); if (!activations_finder.has_code_activations_) { - if (function->code() == *optimized_code) { - if (FLAG_trace_deopt) { - PrintF("[removing optimized code for: "); - function->PrintName(); - PrintF("]\n"); - } - function->ReplaceCode(function->shared()->code()); - } + Deoptimizer::UnlinkOptimizedCode(*optimized_code, + function->context()->native_context()); + // Evict optimized code for this function from the cache so that it // doesn't get used for new closures. function->shared()->EvictFromOptimizedCodeMap(*optimized_code, @@ -348,9 +330,6 @@ RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) { PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n", ast_id.ToInt(), data->OsrPcOffset()->value()); } - // TODO(titzer): this is a massive hack to make the deopt counts - // match. Fix heuristics for reenabling optimizations! - function->shared()->increment_deopt_count(); if (result->is_turbofanned()) { // When we're waiting for concurrent optimization, set to compile on diff --git a/chromium/v8/src/runtime/runtime-debug.cc b/chromium/v8/src/runtime/runtime-debug.cc index 3649621b099..a13d3f95ccc 100644 --- a/chromium/v8/src/runtime/runtime-debug.cc +++ b/chromium/v8/src/runtime/runtime-debug.cc @@ -68,7 +68,7 @@ RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) { SealHandleScope shs(isolate); DCHECK_EQ(0, args.length()); if (isolate->debug()->break_points_active()) { - isolate->debug()->HandleDebugBreak(); + isolate->debug()->HandleDebugBreak(kIgnoreIfTopFrameBlackboxed); } return isolate->heap()->undefined_value(); } @@ -1312,7 +1312,7 @@ RUNTIME_FUNCTION(Runtime_DebugReferencedBy) { // Get the constructor function for context extension and arguments array. Object* arguments_fun = isolate->sloppy_arguments_map()->GetConstructor(); HeapObject* heap_obj; - while ((heap_obj = iterator.next())) { + while ((heap_obj = iterator.next()) != nullptr) { if (!heap_obj->IsJSObject()) continue; JSObject* obj = JSObject::cast(heap_obj); if (obj->IsJSContextExtensionObject()) continue; @@ -1365,7 +1365,7 @@ RUNTIME_FUNCTION(Runtime_DebugConstructedBy) { { HeapIterator iterator(heap, HeapIterator::kFilterUnreachable); HeapObject* heap_obj; - while ((heap_obj = iterator.next())) { + while ((heap_obj = iterator.next()) != nullptr) { if (!heap_obj->IsJSObject()) continue; JSObject* obj = JSObject::cast(heap_obj); if (obj->map()->GetConstructor() != *constructor) continue; @@ -1904,7 +1904,12 @@ RUNTIME_FUNCTION(Runtime_DebugCollectCoverage) { HandleScope scope(isolate); DCHECK_EQ(0, args.length()); // Collect coverage data. - std::unique_ptr<Coverage> coverage(Coverage::Collect(isolate, false)); + std::unique_ptr<Coverage> coverage; + if (isolate->is_best_effort_code_coverage()) { + coverage.reset(Coverage::CollectBestEffort(isolate)); + } else { + coverage.reset(Coverage::CollectPrecise(isolate)); + } Factory* factory = isolate->factory(); // Turn the returned data structure into JavaScript. // Create an array of scripts. @@ -1945,7 +1950,8 @@ RUNTIME_FUNCTION(Runtime_DebugCollectCoverage) { RUNTIME_FUNCTION(Runtime_DebugTogglePreciseCoverage) { SealHandleScope shs(isolate); CONVERT_BOOLEAN_ARG_CHECKED(enable, 0); - Coverage::TogglePrecise(isolate, enable); + Coverage::SelectMode(isolate, enable ? debug::Coverage::kPreciseCount + : debug::Coverage::kBestEffort); return isolate->heap()->undefined_value(); } diff --git a/chromium/v8/src/runtime/runtime-forin.cc b/chromium/v8/src/runtime/runtime-forin.cc index 9a7c5398651..08f6d868192 100644 --- a/chromium/v8/src/runtime/runtime-forin.cc +++ b/chromium/v8/src/runtime/runtime-forin.cc @@ -31,7 +31,7 @@ MaybeHandle<HeapObject> Enumerate(Handle<JSReceiver> receiver) { if (!accumulator.is_receiver_simple_enum()) { Handle<FixedArray> keys; ASSIGN_RETURN_ON_EXCEPTION( - isolate, keys, accumulator.GetKeys(GetKeysConversion::kKeepNumbers), + isolate, keys, accumulator.GetKeys(GetKeysConversion::kConvertToString), HeapObject); // Test again, since cache may have been built by GetKeys() calls above. if (!accumulator.is_receiver_simple_enum()) return keys; diff --git a/chromium/v8/src/runtime/runtime-futex.cc b/chromium/v8/src/runtime/runtime-futex.cc index b6582ffc7f9..5c2106e6859 100644 --- a/chromium/v8/src/runtime/runtime-futex.cc +++ b/chromium/v8/src/runtime/runtime-futex.cc @@ -17,44 +17,6 @@ namespace v8 { namespace internal { -RUNTIME_FUNCTION(Runtime_AtomicsWait) { - HandleScope scope(isolate); - DCHECK_EQ(4, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); - CONVERT_SIZE_ARG_CHECKED(index, 1); - CONVERT_INT32_ARG_CHECKED(value, 2); - CONVERT_DOUBLE_ARG_CHECKED(timeout, 3); - CHECK(sta->GetBuffer()->is_shared()); - CHECK_LT(index, NumberToSize(sta->length())); - CHECK_EQ(sta->type(), kExternalInt32Array); - CHECK(timeout == V8_INFINITY || !std::isnan(timeout)); - - if (!isolate->allow_atomics_wait()) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kAtomicsWaitNotAllowed)); - } - - Handle<JSArrayBuffer> array_buffer = sta->GetBuffer(); - size_t addr = (index << 2) + NumberToSize(sta->byte_offset()); - - return FutexEmulation::Wait(isolate, array_buffer, addr, value, timeout); -} - -RUNTIME_FUNCTION(Runtime_AtomicsWake) { - HandleScope scope(isolate); - DCHECK_EQ(3, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); - CONVERT_SIZE_ARG_CHECKED(index, 1); - CONVERT_UINT32_ARG_CHECKED(count, 2); - CHECK(sta->GetBuffer()->is_shared()); - CHECK_LT(index, NumberToSize(sta->length())); - CHECK_EQ(sta->type(), kExternalInt32Array); - - Handle<JSArrayBuffer> array_buffer = sta->GetBuffer(); - size_t addr = (index << 2) + NumberToSize(sta->byte_offset()); - - return FutexEmulation::Wake(isolate, array_buffer, addr, count); -} RUNTIME_FUNCTION(Runtime_AtomicsNumWaitersForTesting) { HandleScope scope(isolate); diff --git a/chromium/v8/src/runtime/runtime-generator.cc b/chromium/v8/src/runtime/runtime-generator.cc index 96486736e12..0c8fe6db011 100644 --- a/chromium/v8/src/runtime/runtime-generator.cc +++ b/chromium/v8/src/runtime/runtime-generator.cc @@ -77,6 +77,36 @@ RUNTIME_FUNCTION(Runtime_GeneratorGetInputOrDebugPos) { return generator->input_or_debug_pos(); } +RUNTIME_FUNCTION(Runtime_AsyncGeneratorGetAwaitInputOrDebugPos) { + HandleScope scope(isolate); + DCHECK_EQ(1, args.length()); + CONVERT_ARG_HANDLE_CHECKED(JSAsyncGeneratorObject, generator, 0); + + return generator->await_input_or_debug_pos(); +} + +RUNTIME_FUNCTION(Runtime_AsyncGeneratorResolve) { + HandleScope scope(isolate); + DCHECK_EQ(3, args.length()); + + // Runtime call is implemented in InterpreterIntrinsics and lowered in + // JSIntrinsicLowering + UNREACHABLE(); + + return isolate->heap()->undefined_value(); +} + +RUNTIME_FUNCTION(Runtime_AsyncGeneratorReject) { + HandleScope scope(isolate); + DCHECK_EQ(2, args.length()); + + // Runtime call is implemented in InterpreterIntrinsics and lowered in + // JSIntrinsicLowering + UNREACHABLE(); + + return isolate->heap()->undefined_value(); +} + RUNTIME_FUNCTION(Runtime_GeneratorGetResumeMode) { HandleScope scope(isolate); DCHECK_EQ(1, args.length()); diff --git a/chromium/v8/src/runtime/runtime-i18n.cc b/chromium/v8/src/runtime/runtime-i18n.cc index e89175a37db..80c8a9cd012 100644 --- a/chromium/v8/src/runtime/runtime-i18n.cc +++ b/chromium/v8/src/runtime/runtime-i18n.cc @@ -15,7 +15,6 @@ #include "src/i18n.h" #include "src/isolate-inl.h" #include "src/messages.h" -#include "src/string-case.h" #include "src/utils.h" #include "unicode/brkiter.h" @@ -30,7 +29,6 @@ #include "unicode/fieldpos.h" #include "unicode/fpositer.h" #include "unicode/locid.h" -#include "unicode/normalizer2.h" #include "unicode/numfmt.h" #include "unicode/numsys.h" #include "unicode/rbbi.h" @@ -49,24 +47,6 @@ namespace v8 { namespace internal { -namespace { - -const UChar* GetUCharBufferFromFlat(const String::FlatContent& flat, - std::unique_ptr<uc16[]>* dest, - int32_t length) { - DCHECK(flat.IsFlat()); - if (flat.IsOneByte()) { - if (!*dest) { - dest->reset(NewArray<uc16>(length)); - CopyChars(dest->get(), flat.ToOneByteVector().start(), length); - } - return reinterpret_cast<const UChar*>(dest->get()); - } else { - return reinterpret_cast<const UChar*>(flat.ToUC16Vector().start()); - } -} - -} // namespace // ECMA 402 6.2.3 RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) { @@ -322,13 +302,13 @@ RUNTIME_FUNCTION(Runtime_CreateDateTimeFormat) { ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, local_object, JSObject::New(constructor, constructor)); - // Set date time formatter as internal field of the resulting JS object. + // Set date time formatter as embedder field of the resulting JS object. icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat(isolate, locale, options, resolved); if (!date_format) return isolate->ThrowIllegalOperation(); - local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format)); + local_object->SetEmbedderField(0, reinterpret_cast<Smi*>(date_format)); // Make object handle weak so we can delete the data format once GC kicks in. Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); @@ -512,13 +492,13 @@ RUNTIME_FUNCTION(Runtime_CreateNumberFormat) { ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, local_object, JSObject::New(constructor, constructor)); - // Set number formatter as internal field of the resulting JS object. + // Set number formatter as embedder field of the resulting JS object. icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat(isolate, locale, options, resolved); if (!number_format) return isolate->ThrowIllegalOperation(); - local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format)); + local_object->SetEmbedderField(0, reinterpret_cast<Smi*>(number_format)); Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(), @@ -552,6 +532,29 @@ RUNTIME_FUNCTION(Runtime_InternalNumberFormat) { result.length()))); } +RUNTIME_FUNCTION(Runtime_CurrencyDigits) { + DCHECK_EQ(1, args.length()); + + CONVERT_ARG_HANDLE_CHECKED(String, currency, 0); + + // TODO(littledan): Avoid transcoding the string twice + v8::String::Utf8Value currency_string(v8::Utils::ToLocal(currency)); + icu::UnicodeString currency_icu = + icu::UnicodeString::fromUTF8(*currency_string); + + DisallowHeapAllocation no_gc; + UErrorCode status = U_ZERO_ERROR; +#if U_ICU_VERSION_MAJOR_NUM >= 59 + uint32_t fraction_digits = ucurr_getDefaultFractionDigits( + icu::toUCharPtr(currency_icu.getTerminatedBuffer()), &status); +#else + uint32_t fraction_digits = ucurr_getDefaultFractionDigits( + currency_icu.getTerminatedBuffer(), &status); +#endif + // For missing currency codes, default to the most common, 2 + if (!U_SUCCESS(status)) fraction_digits = 2; + return Smi::FromInt(fraction_digits); +} RUNTIME_FUNCTION(Runtime_CreateCollator) { HandleScope scope(isolate); @@ -569,13 +572,13 @@ RUNTIME_FUNCTION(Runtime_CreateCollator) { ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, local_object, JSObject::New(constructor, constructor)); - // Set collator as internal field of the resulting JS object. + // Set collator as embedder field of the resulting JS object. icu::Collator* collator = Collator::InitializeCollator(isolate, locale, options, resolved); if (!collator) return isolate->ThrowIllegalOperation(); - local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator)); + local_object->SetEmbedderField(0, reinterpret_cast<Smi*>(collator)); Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(), @@ -622,64 +625,6 @@ RUNTIME_FUNCTION(Runtime_InternalCompare) { } -RUNTIME_FUNCTION(Runtime_StringNormalize) { - HandleScope scope(isolate); - static const struct { - const char* name; - UNormalization2Mode mode; - } normalizationForms[] = { - {"nfc", UNORM2_COMPOSE}, - {"nfc", UNORM2_DECOMPOSE}, - {"nfkc", UNORM2_COMPOSE}, - {"nfkc", UNORM2_DECOMPOSE}, - }; - - DCHECK_EQ(2, args.length()); - - CONVERT_ARG_HANDLE_CHECKED(String, s, 0); - CONVERT_NUMBER_CHECKED(int, form_id, Int32, args[1]); - CHECK(form_id >= 0 && - static_cast<size_t>(form_id) < arraysize(normalizationForms)); - - int length = s->length(); - s = String::Flatten(s); - icu::UnicodeString result; - std::unique_ptr<uc16[]> sap; - UErrorCode status = U_ZERO_ERROR; - { - DisallowHeapAllocation no_gc; - String::FlatContent flat = s->GetFlatContent(); - const UChar* src = GetUCharBufferFromFlat(flat, &sap, length); - icu::UnicodeString input(false, src, length); - // Getting a singleton. Should not free it. - const icu::Normalizer2* normalizer = - icu::Normalizer2::getInstance(nullptr, normalizationForms[form_id].name, - normalizationForms[form_id].mode, status); - DCHECK(U_SUCCESS(status)); - CHECK(normalizer != nullptr); - int32_t normalized_prefix_length = - normalizer->spanQuickCheckYes(input, status); - // Quick return if the input is already normalized. - if (length == normalized_prefix_length) return *s; - icu::UnicodeString unnormalized = - input.tempSubString(normalized_prefix_length); - // Read-only alias of the normalized prefix. - result.setTo(false, input.getBuffer(), normalized_prefix_length); - // copy-on-write; normalize the suffix and append to |result|. - normalizer->normalizeSecondAndAppend(result, unnormalized, status); - } - - if (U_FAILURE(status)) { - return isolate->heap()->undefined_value(); - } - - RETURN_RESULT_OR_FAILURE( - isolate, isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>( - reinterpret_cast<const uint16_t*>(result.getBuffer()), - result.length()))); -} - - RUNTIME_FUNCTION(Runtime_CreateBreakIterator) { HandleScope scope(isolate); @@ -696,15 +641,15 @@ RUNTIME_FUNCTION(Runtime_CreateBreakIterator) { ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, local_object, JSObject::New(constructor, constructor)); - // Set break iterator as internal field of the resulting JS object. + // Set break iterator as embedder field of the resulting JS object. icu::BreakIterator* break_iterator = V8BreakIterator::InitializeBreakIterator( isolate, locale, options, resolved); if (!break_iterator) return isolate->ThrowIllegalOperation(); - local_object->SetInternalField(0, reinterpret_cast<Smi*>(break_iterator)); + local_object->SetEmbedderField(0, reinterpret_cast<Smi*>(break_iterator)); // Make sure that the pointer to adopted text is NULL. - local_object->SetInternalField(1, static_cast<Smi*>(nullptr)); + local_object->SetEmbedderField(1, static_cast<Smi*>(nullptr)); // Make object handle weak so we can delete the break iterator once GC kicks // in. @@ -729,7 +674,7 @@ RUNTIME_FUNCTION(Runtime_BreakIteratorAdoptText) { CHECK_NOT_NULL(break_iterator); icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>( - break_iterator_holder->GetInternalField(1)); + break_iterator_holder->GetEmbedderField(1)); delete u_text; int length = text->length(); @@ -739,7 +684,7 @@ RUNTIME_FUNCTION(Runtime_BreakIteratorAdoptText) { std::unique_ptr<uc16[]> sap; const UChar* text_value = GetUCharBufferFromFlat(flat, &sap, length); u_text = new icu::UnicodeString(text_value, length); - break_iterator_holder->SetInternalField(1, reinterpret_cast<Smi*>(u_text)); + break_iterator_holder->SetEmbedderField(1, reinterpret_cast<Smi*>(u_text)); break_iterator->setText(*u_text); @@ -823,295 +768,6 @@ RUNTIME_FUNCTION(Runtime_BreakIteratorBreakType) { } } -namespace { -MUST_USE_RESULT Object* LocaleConvertCase(Handle<String> s, Isolate* isolate, - bool is_to_upper, const char* lang) { - auto case_converter = is_to_upper ? u_strToUpper : u_strToLower; - int32_t src_length = s->length(); - int32_t dest_length = src_length; - UErrorCode status; - Handle<SeqTwoByteString> result; - std::unique_ptr<uc16[]> sap; - - if (dest_length == 0) return isolate->heap()->empty_string(); - - // This is not a real loop. It'll be executed only once (no overflow) or - // twice (overflow). - for (int i = 0; i < 2; ++i) { - // Case conversion can increase the string length (e.g. sharp-S => SS) so - // that we have to handle RangeError exceptions here. - ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, result, isolate->factory()->NewRawTwoByteString(dest_length)); - DisallowHeapAllocation no_gc; - DCHECK(s->IsFlat()); - String::FlatContent flat = s->GetFlatContent(); - const UChar* src = GetUCharBufferFromFlat(flat, &sap, src_length); - status = U_ZERO_ERROR; - dest_length = case_converter(reinterpret_cast<UChar*>(result->GetChars()), - dest_length, src, src_length, lang, &status); - if (status != U_BUFFER_OVERFLOW_ERROR) break; - } - - // In most cases, the output will fill the destination buffer completely - // leading to an unterminated string (U_STRING_NOT_TERMINATED_WARNING). - // Only in rare cases, it'll be shorter than the destination buffer and - // |result| has to be truncated. - DCHECK(U_SUCCESS(status)); - if (V8_LIKELY(status == U_STRING_NOT_TERMINATED_WARNING)) { - DCHECK(dest_length == result->length()); - return *result; - } - if (U_SUCCESS(status)) { - DCHECK(dest_length < result->length()); - return *Handle<SeqTwoByteString>::cast( - SeqString::Truncate(result, dest_length)); - } - return *s; -} - -inline bool IsASCIIUpper(uint16_t ch) { return ch >= 'A' && ch <= 'Z'; } - -const uint8_t kToLower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, - 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, - 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, - 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, - 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, - 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, - 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, - 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, - 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xD7, - 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, - 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, - 0xFC, 0xFD, 0xFE, 0xFF, -}; - -inline uint16_t ToLatin1Lower(uint16_t ch) { - return static_cast<uint16_t>(kToLower[ch]); -} - -inline uint16_t ToASCIIUpper(uint16_t ch) { - return ch & ~((ch >= 'a' && ch <= 'z') << 5); -} - -// Does not work for U+00DF (sharp-s), U+00B5 (micron), U+00FF. -inline uint16_t ToLatin1Upper(uint16_t ch) { - DCHECK(ch != 0xDF && ch != 0xB5 && ch != 0xFF); - return ch & - ~(((ch >= 'a' && ch <= 'z') || (((ch & 0xE0) == 0xE0) && ch != 0xF7)) - << 5); -} - -template <typename Char> -bool ToUpperFastASCII(const Vector<const Char>& src, - Handle<SeqOneByteString> result) { - // Do a faster loop for the case where all the characters are ASCII. - uint16_t ored = 0; - int32_t index = 0; - for (auto it = src.begin(); it != src.end(); ++it) { - uint16_t ch = static_cast<uint16_t>(*it); - ored |= ch; - result->SeqOneByteStringSet(index++, ToASCIIUpper(ch)); - } - return !(ored & ~0x7F); -} - -const uint16_t sharp_s = 0xDF; - -template <typename Char> -bool ToUpperOneByte(const Vector<const Char>& src, uint8_t* dest, - int* sharp_s_count) { - // Still pretty-fast path for the input with non-ASCII Latin-1 characters. - - // There are two special cases. - // 1. U+00B5 and U+00FF are mapped to a character beyond U+00FF. - // 2. Lower case sharp-S converts to "SS" (two characters) - *sharp_s_count = 0; - for (auto it = src.begin(); it != src.end(); ++it) { - uint16_t ch = static_cast<uint16_t>(*it); - if (V8_UNLIKELY(ch == sharp_s)) { - ++(*sharp_s_count); - continue; - } - if (V8_UNLIKELY(ch == 0xB5 || ch == 0xFF)) { - // Since this upper-cased character does not fit in an 8-bit string, we - // need to take the 16-bit path. - return false; - } - *dest++ = ToLatin1Upper(ch); - } - - return true; -} - -template <typename Char> -void ToUpperWithSharpS(const Vector<const Char>& src, - Handle<SeqOneByteString> result) { - int32_t dest_index = 0; - for (auto it = src.begin(); it != src.end(); ++it) { - uint16_t ch = static_cast<uint16_t>(*it); - if (ch == sharp_s) { - result->SeqOneByteStringSet(dest_index++, 'S'); - result->SeqOneByteStringSet(dest_index++, 'S'); - } else { - result->SeqOneByteStringSet(dest_index++, ToLatin1Upper(ch)); - } - } -} - -inline int FindFirstUpperOrNonAscii(Handle<String> s, int length) { - for (int index = 0; index < length; ++index) { - uint16_t ch = s->Get(index); - if (V8_UNLIKELY(IsASCIIUpper(ch) || ch & ~0x7F)) { - return index; - } - } - return length; -} - -MUST_USE_RESULT Object* ConvertToLower(Handle<String> s, Isolate* isolate) { - if (!s->HasOnlyOneByteChars()) { - // Use a slower implementation for strings with characters beyond U+00FF. - return LocaleConvertCase(s, isolate, false, ""); - } - - int length = s->length(); - - // We depend here on the invariant that the length of a Latin1 - // string is invariant under ToLowerCase, and the result always - // fits in the Latin1 range in the *root locale*. It does not hold - // for ToUpperCase even in the root locale. - - // Scan the string for uppercase and non-ASCII characters for strings - // shorter than a machine-word without any memory allocation overhead. - // TODO(jshin): Apply this to a longer input by breaking FastAsciiConvert() - // to two parts, one for scanning the prefix with no change and the other for - // handling ASCII-only characters. - int index_to_first_unprocessed = length; - const bool is_short = length < static_cast<int>(sizeof(uintptr_t)); - if (is_short) { - index_to_first_unprocessed = FindFirstUpperOrNonAscii(s, length); - // Nothing to do if the string is all ASCII with no uppercase. - if (index_to_first_unprocessed == length) return *s; - } - - Handle<SeqOneByteString> result = - isolate->factory()->NewRawOneByteString(length).ToHandleChecked(); - - DisallowHeapAllocation no_gc; - DCHECK(s->IsFlat()); - String::FlatContent flat = s->GetFlatContent(); - uint8_t* dest = result->GetChars(); - if (flat.IsOneByte()) { - const uint8_t* src = flat.ToOneByteVector().start(); - bool has_changed_character = false; - index_to_first_unprocessed = FastAsciiConvert<true>( - reinterpret_cast<char*>(dest), reinterpret_cast<const char*>(src), - length, &has_changed_character); - // If not ASCII, we keep the result up to index_to_first_unprocessed and - // process the rest. - if (index_to_first_unprocessed == length) - return has_changed_character ? *result : *s; - - for (int index = index_to_first_unprocessed; index < length; ++index) { - dest[index] = ToLatin1Lower(static_cast<uint16_t>(src[index])); - } - } else { - if (index_to_first_unprocessed == length) { - DCHECK(!is_short); - index_to_first_unprocessed = FindFirstUpperOrNonAscii(s, length); - } - // Nothing to do if the string is all ASCII with no uppercase. - if (index_to_first_unprocessed == length) return *s; - const uint16_t* src = flat.ToUC16Vector().start(); - CopyChars(dest, src, index_to_first_unprocessed); - for (int index = index_to_first_unprocessed; index < length; ++index) { - dest[index] = ToLatin1Lower(static_cast<uint16_t>(src[index])); - } - } - - return *result; -} - -MUST_USE_RESULT Object* ConvertToUpper(Handle<String> s, Isolate* isolate) { - int32_t length = s->length(); - if (s->HasOnlyOneByteChars() && length > 0) { - Handle<SeqOneByteString> result = - isolate->factory()->NewRawOneByteString(length).ToHandleChecked(); - - DCHECK(s->IsFlat()); - int sharp_s_count; - bool is_result_single_byte; - { - DisallowHeapAllocation no_gc; - String::FlatContent flat = s->GetFlatContent(); - uint8_t* dest = result->GetChars(); - if (flat.IsOneByte()) { - Vector<const uint8_t> src = flat.ToOneByteVector(); - bool has_changed_character = false; - int index_to_first_unprocessed = - FastAsciiConvert<false>(reinterpret_cast<char*>(result->GetChars()), - reinterpret_cast<const char*>(src.start()), - length, &has_changed_character); - if (index_to_first_unprocessed == length) - return has_changed_character ? *result : *s; - // If not ASCII, we keep the result up to index_to_first_unprocessed and - // process the rest. - is_result_single_byte = - ToUpperOneByte(src.SubVector(index_to_first_unprocessed, length), - dest + index_to_first_unprocessed, &sharp_s_count); - } else { - DCHECK(flat.IsTwoByte()); - Vector<const uint16_t> src = flat.ToUC16Vector(); - if (ToUpperFastASCII(src, result)) return *result; - is_result_single_byte = ToUpperOneByte(src, dest, &sharp_s_count); - } - } - - // Go to the full Unicode path if there are characters whose uppercase - // is beyond the Latin-1 range (cannot be represented in OneByteString). - if (V8_UNLIKELY(!is_result_single_byte)) { - return LocaleConvertCase(s, isolate, true, ""); - } - - if (sharp_s_count == 0) return *result; - - // We have sharp_s_count sharp-s characters, but the result is still - // in the Latin-1 range. - ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, result, - isolate->factory()->NewRawOneByteString(length + sharp_s_count)); - DisallowHeapAllocation no_gc; - String::FlatContent flat = s->GetFlatContent(); - if (flat.IsOneByte()) { - ToUpperWithSharpS(flat.ToOneByteVector(), result); - } else { - ToUpperWithSharpS(flat.ToUC16Vector(), result); - } - - return *result; - } - - return LocaleConvertCase(s, isolate, true, ""); -} - -MUST_USE_RESULT Object* ConvertCase(Handle<String> s, bool is_upper, - Isolate* isolate) { - return is_upper ? ConvertToUpper(s, isolate) : ConvertToLower(s, isolate); -} - -} // namespace - RUNTIME_FUNCTION(Runtime_StringToLowerCaseI18N) { HandleScope scope(isolate); DCHECK_EQ(args.length(), 1); diff --git a/chromium/v8/src/runtime/runtime-internal.cc b/chromium/v8/src/runtime/runtime-internal.cc index 83995098c0a..8c566c081db 100644 --- a/chromium/v8/src/runtime/runtime-internal.cc +++ b/chromium/v8/src/runtime/runtime-internal.cc @@ -95,21 +95,70 @@ RUNTIME_FUNCTION(Runtime_ThrowSymbolAsyncIteratorInvalid) { isolate, NewTypeError(MessageTemplate::kSymbolAsyncIteratorInvalid)); } +#define THROW_ERROR(isolate, args, call) \ + HandleScope scope(isolate); \ + DCHECK_LE(1, args.length()); \ + CONVERT_SMI_ARG_CHECKED(message_id_smi, 0); \ + \ + Handle<Object> undefined = isolate->factory()->undefined_value(); \ + Handle<Object> arg0 = (args.length() > 1) ? args.at(1) : undefined; \ + Handle<Object> arg1 = (args.length() > 2) ? args.at(2) : undefined; \ + Handle<Object> arg2 = (args.length() > 3) ? args.at(3) : undefined; \ + \ + MessageTemplate::Template message_id = \ + static_cast<MessageTemplate::Template>(message_id_smi); \ + \ + THROW_NEW_ERROR_RETURN_FAILURE(isolate, call(message_id, arg0, arg1, arg2)); + +RUNTIME_FUNCTION(Runtime_ThrowRangeError) { + THROW_ERROR(isolate, args, NewRangeError); +} + RUNTIME_FUNCTION(Runtime_ThrowTypeError) { + THROW_ERROR(isolate, args, NewTypeError); +} + +#undef THROW_ERROR + +namespace { + +const char* ElementsKindToType(ElementsKind fixed_elements_kind) { + switch (fixed_elements_kind) { +#define ELEMENTS_KIND_CASE(Type, type, TYPE, ctype, size) \ + case TYPE##_ELEMENTS: \ + return #Type "Array"; + + TYPED_ARRAYS(ELEMENTS_KIND_CASE) +#undef ELEMENTS_KIND_CASE + + default: + UNREACHABLE(); + return ""; + } +} + +} // namespace + +RUNTIME_FUNCTION(Runtime_ThrowInvalidTypedArrayAlignment) { HandleScope scope(isolate); - DCHECK_LE(1, args.length()); - CONVERT_SMI_ARG_CHECKED(message_id_smi, 0); + DCHECK_EQ(2, args.length()); + CONVERT_ARG_HANDLE_CHECKED(Map, map, 0); + CONVERT_ARG_HANDLE_CHECKED(String, problem_string, 1); - Handle<Object> undefined = isolate->factory()->undefined_value(); - Handle<Object> arg0 = (args.length() > 1) ? args.at(1) : undefined; - Handle<Object> arg1 = (args.length() > 2) ? args.at(2) : undefined; - Handle<Object> arg2 = (args.length() > 3) ? args.at(3) : undefined; + ElementsKind kind = map->elements_kind(); - MessageTemplate::Template message_id = - static_cast<MessageTemplate::Template>(message_id_smi); + Handle<String> type = + isolate->factory()->NewStringFromAsciiChecked(ElementsKindToType(kind)); - THROW_NEW_ERROR_RETURN_FAILURE(isolate, - NewTypeError(message_id, arg0, arg1, arg2)); + ExternalArrayType external_type = + isolate->factory()->GetArrayTypeFromElementsKind(kind); + size_t size = isolate->factory()->GetExternalArrayElementSize(external_type); + Handle<Object> element_size = + handle(Smi::FromInt(static_cast<int>(size)), isolate); + + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewRangeError(MessageTemplate::kInvalidTypedArrayAlignment, + problem_string, type, element_size)); } RUNTIME_FUNCTION(Runtime_UnwindAndFindExceptionHandler) { @@ -367,7 +416,7 @@ Handle<String> RenderCallSite(Isolate* isolate, Handle<Object> object) { MessageLocation location; if (ComputeLocation(isolate, &location)) { std::unique_ptr<ParseInfo> info(new ParseInfo(location.shared())); - if (parsing::ParseAny(info.get())) { + if (parsing::ParseAny(info.get(), isolate)) { CallPrinter printer(isolate, location.shared()->IsUserJavaScript()); Handle<String> str = printer.Print(info->literal(), location.start_pos()); if (str->length() > 0) return str; diff --git a/chromium/v8/src/runtime/runtime-liveedit.cc b/chromium/v8/src/runtime/runtime-liveedit.cc index 56493252c8f..fa49df88dad 100644 --- a/chromium/v8/src/runtime/runtime-liveedit.cc +++ b/chromium/v8/src/runtime/runtime-liveedit.cc @@ -32,7 +32,7 @@ RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) { { HeapIterator iterator(heap); HeapObject* heap_obj; - while ((heap_obj = iterator.next())) { + while ((heap_obj = iterator.next()) != nullptr) { if (!heap_obj->IsSharedFunctionInfo()) continue; SharedFunctionInfo* shared = SharedFunctionInfo::cast(heap_obj); if (shared->script() != *script) continue; diff --git a/chromium/v8/src/runtime/runtime-maths.cc b/chromium/v8/src/runtime/runtime-maths.cc index 4cb4f006ff3..bb8436cd110 100644 --- a/chromium/v8/src/runtime/runtime-maths.cc +++ b/chromium/v8/src/runtime/runtime-maths.cc @@ -41,10 +41,18 @@ RUNTIME_FUNCTION(Runtime_GenerateRandomNumbers) { cache = Handle<FixedDoubleArray>::cast( isolate->factory()->NewFixedDoubleArray(kCacheSize, TENURED)); native_context->set_math_random_cache(*cache); - // Initialize state if not yet initialized. - while (state0 == 0 || state1 == 0) { - isolate->random_number_generator()->NextBytes(&state0, sizeof(state0)); - isolate->random_number_generator()->NextBytes(&state1, sizeof(state1)); + // Initialize state if not yet initialized. If a fixed random seed was + // requested, use it to reset our state the first time a script asks for + // random numbers in this context. This ensures the script sees a consistent + // sequence. + if (FLAG_random_seed != 0) { + state0 = FLAG_random_seed; + state1 = FLAG_random_seed; + } else { + while (state0 == 0 || state1 == 0) { + isolate->random_number_generator()->NextBytes(&state0, sizeof(state0)); + isolate->random_number_generator()->NextBytes(&state1, sizeof(state1)); + } } } diff --git a/chromium/v8/src/runtime/runtime-module.cc b/chromium/v8/src/runtime/runtime-module.cc index f36a09b410b..3c896d8c566 100644 --- a/chromium/v8/src/runtime/runtime-module.cc +++ b/chromium/v8/src/runtime/runtime-module.cc @@ -13,9 +13,36 @@ namespace internal { RUNTIME_FUNCTION(Runtime_DynamicImportCall) { HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - // TODO(gsathya): Implement ImportCall. - return isolate->heap()->undefined_value(); + DCHECK_EQ(2, args.length()); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); + CONVERT_ARG_HANDLE_CHECKED(Object, specifier, 1); + + Handle<JSPromise> promise = isolate->factory()->NewJSPromise(); + + Handle<String> specifier_str; + MaybeHandle<String> maybe_specifier = Object::ToString(isolate, specifier); + if (!maybe_specifier.ToHandle(&specifier_str)) { + DCHECK(isolate->has_pending_exception()); + Handle<Object> reason(isolate->pending_exception(), isolate); + isolate->clear_pending_exception(); + + Handle<Object> argv[] = {promise, reason, + isolate->factory()->ToBoolean(false)}; + + RETURN_FAILURE_ON_EXCEPTION( + isolate, Execution::Call(isolate, isolate->promise_internal_reject(), + isolate->factory()->undefined_value(), + arraysize(argv), argv)) + return *promise; + } + DCHECK(!isolate->has_pending_exception()); + + Handle<Script> script(Script::cast(function->shared()->script())); + Handle<String> source_url(String::cast(script->name())); + + isolate->RunHostImportModuleDynamicallyCallback(source_url, specifier_str, + promise); + return *promise; } RUNTIME_FUNCTION(Runtime_GetModuleNamespace) { diff --git a/chromium/v8/src/runtime/runtime-numbers.cc b/chromium/v8/src/runtime/runtime-numbers.cc index 4d8d5d267db..72d2403c173 100644 --- a/chromium/v8/src/runtime/runtime-numbers.cc +++ b/chromium/v8/src/runtime/runtime-numbers.cc @@ -213,13 +213,6 @@ RUNTIME_FUNCTION(Runtime_IsSmi) { } -RUNTIME_FUNCTION(Runtime_GetRootNaN) { - SealHandleScope shs(isolate); - DCHECK_EQ(0, args.length()); - return isolate->heap()->nan_value(); -} - - RUNTIME_FUNCTION(Runtime_GetHoleNaNUpper) { HandleScope scope(isolate); DCHECK_EQ(0, args.length()); diff --git a/chromium/v8/src/runtime/runtime-object.cc b/chromium/v8/src/runtime/runtime-object.cc index dd24728457d..4c34b0e563f 100644 --- a/chromium/v8/src/runtime/runtime-object.cc +++ b/chromium/v8/src/runtime/runtime-object.cc @@ -50,20 +50,21 @@ static MaybeHandle<Object> KeyedGetObjectProperty(Isolate* isolate, // // Additionally, we need to make sure that we do not cache results // for objects that require access checks. + + // Convert string-index keys to their number variant to avoid internalization + // below; and speed up subsequent conversion to index. + uint32_t index; + if (key_obj->IsString() && String::cast(*key_obj)->AsArrayIndex(&index)) { + key_obj = isolate->factory()->NewNumberFromUint(index); + } if (receiver_obj->IsJSObject()) { if (!receiver_obj->IsJSGlobalProxy() && !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) { - DisallowHeapAllocation no_allocation; Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj); Handle<Name> key = Handle<Name>::cast(key_obj); - // Get to a ThinString's referenced internalized string, but don't - // otherwise force internalization. We assume that internalization - // (which is a dictionary lookup with a non-internalized key) is - // about as expensive as doing the property dictionary lookup with - // the non-internalized key directly. - if (key->IsThinString()) { - key = handle(Handle<ThinString>::cast(key)->actual(), isolate); - } + key_obj = key = isolate->factory()->InternalizeName(key); + + DisallowHeapAllocation no_allocation; if (receiver->IsJSGlobalObject()) { // Attempt dictionary lookup. GlobalDictionary* dictionary = receiver->global_dictionary(); @@ -215,6 +216,23 @@ RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty) { return isolate->heap()->false_value(); } +RUNTIME_FUNCTION(Runtime_AddDictionaryProperty) { + HandleScope scope(isolate); + Handle<JSObject> receiver = args.at<JSObject>(0); + Handle<Name> name = args.at<Name>(1); + Handle<Object> value = args.at(2); + + DCHECK(name->IsUniqueName()); + + Handle<NameDictionary> dictionary(receiver->property_dictionary(), isolate); + int entry; + PropertyDetails property_details(kData, NONE, 0, PropertyCellType::kNoCell); + dictionary = + NameDictionary::Add(dictionary, name, value, property_details, &entry); + receiver->set_properties(*dictionary); + return *value; +} + // ES6 section 19.1.2.2 Object.create ( O [ , Properties ] ) // TODO(verwaest): Support the common cases with precached map directly in // an Object.create stub. @@ -648,12 +666,12 @@ RUNTIME_FUNCTION(Runtime_DefineDataPropertyInLiteral) { if (name->IsUniqueName()) { nexus.ConfigureMonomorphic(name, handle(object->map())); } else { - nexus.ConfigureMegamorphic(); + nexus.ConfigureMegamorphic(PROPERTY); } } else if (nexus.ic_state() == MONOMORPHIC) { if (nexus.FindFirstMap() != object->map() || nexus.GetFeedbackExtra() != *name) { - nexus.ConfigureMegamorphic(); + nexus.ConfigureMegamorphic(PROPERTY); } } @@ -680,6 +698,28 @@ RUNTIME_FUNCTION(Runtime_DefineDataPropertyInLiteral) { return *object; } +RUNTIME_FUNCTION(Runtime_CollectTypeProfile) { + HandleScope scope(isolate); + DCHECK_EQ(3, args.length()); + CONVERT_ARG_HANDLE_CHECKED(Smi, position, 0); + CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); + CONVERT_ARG_HANDLE_CHECKED(FeedbackVector, vector, 2); + + DCHECK(FLAG_type_profile); + + Handle<String> type = Object::TypeOf(isolate, value); + if (value->IsJSReceiver()) { + Handle<JSReceiver> object = Handle<JSReceiver>::cast(value); + type = JSReceiver::GetConstructorName(object); + } + + DCHECK(vector->metadata()->HasTypeProfileSlot()); + CollectTypeProfileNexus nexus(vector, vector->GetTypeProfileSlot()); + nexus.Collect(type, position->value()); + + return isolate->heap()->undefined_value(); +} + // Return property without being observable by accessors or interceptors. RUNTIME_FUNCTION(Runtime_GetDataProperty) { HandleScope scope(isolate); @@ -988,6 +1028,22 @@ RUNTIME_FUNCTION(Runtime_CreateDataProperty) { return *value; } +// Checks that 22.2.2.1.1 Runtime Semantics: IterableToList produces exactly the +// same result as doing nothing. +RUNTIME_FUNCTION(Runtime_IterableToListCanBeElided) { + HandleScope scope(isolate); + DCHECK_EQ(1, args.length()); + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0); + + if (!obj->IsJSObject()) return isolate->heap()->ToBoolean(false); + + // While iteration alone may not have observable side-effects, calling + // toNumber on an object will. Make sure the arg is not an array of objects. + ElementsKind kind = JSObject::cast(*obj)->GetElementsKind(); + if (!IsFastNumberElementsKind(kind)) return isolate->heap()->ToBoolean(false); + + return isolate->heap()->ToBoolean(!obj->IterationHasObservableEffects()); +} } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/runtime/runtime-regexp.cc b/chromium/v8/src/runtime/runtime-regexp.cc index aec95565109..c9f201c11d5 100644 --- a/chromium/v8/src/runtime/runtime-regexp.cc +++ b/chromium/v8/src/runtime/runtime-regexp.cc @@ -4,6 +4,8 @@ #include "src/runtime/runtime-utils.h" +#include <functional> + #include "src/arguments.h" #include "src/conversions-inl.h" #include "src/isolate-inl.h" @@ -17,14 +19,45 @@ namespace v8 { namespace internal { +namespace { + +// Looks up the capture of the given name. Returns the (1-based) numbered +// capture index or -1 on failure. +int LookupNamedCapture(std::function<bool(String*)> name_matches, + FixedArray* capture_name_map) { + // TODO(jgruber): Sort capture_name_map and do binary search via + // internalized strings. + + int maybe_capture_index = -1; + const int named_capture_count = capture_name_map->length() >> 1; + for (int j = 0; j < named_capture_count; j++) { + // The format of {capture_name_map} is documented at + // JSRegExp::kIrregexpCaptureNameMapIndex. + const int name_ix = j * 2; + const int index_ix = j * 2 + 1; + + String* capture_name = String::cast(capture_name_map->get(name_ix)); + if (!name_matches(capture_name)) continue; + + maybe_capture_index = Smi::cast(capture_name_map->get(index_ix))->value(); + break; + } + + return maybe_capture_index; +} + +} // namespace + class CompiledReplacement { public: explicit CompiledReplacement(Zone* zone) : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {} - // Return whether the replacement is simple. - bool Compile(Handle<String> replacement, int capture_count, - int subject_length); + // Return whether the replacement is simple. Can also fail and return Nothing + // if the given replacement string is invalid (and requires throwing a + // SyntaxError). + Maybe<bool> Compile(Handle<JSRegExp> regexp, Handle<String> replacement, + int capture_count, int subject_length); // Use Apply only if Compile returned false. void Apply(ReplacementStringBuilder* builder, int match_from, int match_to, @@ -91,9 +124,17 @@ class CompiledReplacement { }; template <typename Char> - bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts, - Vector<Char> characters, int capture_count, - int subject_length, Zone* zone) { + Maybe<bool> ParseReplacementPattern(ZoneList<ReplacementPart>* parts, + Vector<Char> characters, + FixedArray* capture_name_map, + int capture_count, int subject_length, + Zone* zone) { + // Equivalent to String::GetSubstitution, except that this method converts + // the replacement string into an internal representation that avoids + // repeated parsing when used repeatedly. + DCHECK_IMPLIES(capture_name_map != nullptr, + FLAG_harmony_regexp_named_captures); + int length = characters.length(); int last = 0; for (int i = 0; i < length; i++) { @@ -181,6 +222,57 @@ class CompiledReplacement { i = next_index; break; } + case '<': { + if (capture_name_map == nullptr) { + i = next_index; + break; + } + + // Scan until the next '>', throwing a SyntaxError exception if one + // is not found, and let the enclosed substring be groupName. + + const int name_start_index = next_index + 1; + int closing_bracket_index = -1; + for (int j = name_start_index; j < length; j++) { + if (characters[j] == '>') { + closing_bracket_index = j; + break; + } + } + + // Throw a SyntaxError for invalid replacement strings. + if (closing_bracket_index == -1) return Nothing<bool>(); + + Vector<Char> requested_name = + characters.SubVector(name_start_index, closing_bracket_index); + + // Let capture be ? Get(namedCaptures, groupName). + + const int capture_index = LookupNamedCapture( + [=](String* capture_name) { + return capture_name->IsEqualTo(requested_name); + }, + capture_name_map); + + // If ? HasProperty(_namedCaptures_, _groupName_) is *false*, throw + // a *SyntaxError* exception. + if (capture_index == -1) return Nothing<bool>(); + + // If capture is undefined, replace the text through the following + // '>' with the empty string. + // Otherwise, replace the text through the following '>' with + // ? ToString(capture). + + DCHECK(1 <= capture_index && capture_index <= capture_count); + + if (i > last) { + parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); + } + parts->Add(ReplacementPart::SubjectCapture(capture_index), zone); + last = closing_bracket_index + 1; + i = closing_bracket_index; + break; + } default: i = next_index; break; @@ -190,12 +282,12 @@ class CompiledReplacement { if (length > last) { if (last == 0) { // Replacement is simple. Do not use Apply to do the replacement. - return true; + return Just(true); } else { parts->Add(ReplacementPart::ReplacementSubString(last, length), zone); } } - return false; + return Just(false); } ZoneList<ReplacementPart> parts_; @@ -203,23 +295,37 @@ class CompiledReplacement { Zone* zone_; }; - -bool CompiledReplacement::Compile(Handle<String> replacement, int capture_count, - int subject_length) { +Maybe<bool> CompiledReplacement::Compile(Handle<JSRegExp> regexp, + Handle<String> replacement, + int capture_count, + int subject_length) { { DisallowHeapAllocation no_gc; String::FlatContent content = replacement->GetFlatContent(); DCHECK(content.IsFlat()); - bool simple = false; + + FixedArray* capture_name_map = nullptr; + if (capture_count > 0) { + DCHECK_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP); + Object* maybe_capture_name_map = regexp->CaptureNameMap(); + if (maybe_capture_name_map->IsFixedArray()) { + DCHECK(FLAG_harmony_regexp_named_captures); + capture_name_map = FixedArray::cast(maybe_capture_name_map); + } + } + + Maybe<bool> simple = Nothing<bool>(); if (content.IsOneByte()) { simple = ParseReplacementPattern(&parts_, content.ToOneByteVector(), - capture_count, subject_length, zone()); + capture_name_map, capture_count, + subject_length, zone()); } else { DCHECK(content.IsTwoByte()); simple = ParseReplacementPattern(&parts_, content.ToUC16Vector(), - capture_count, subject_length, zone()); + capture_name_map, capture_count, + subject_length, zone()); } - if (simple) return true; + if (simple.IsNothing() || simple.FromJust()) return simple; } Isolate* isolate = replacement->GetIsolate(); @@ -241,7 +347,7 @@ bool CompiledReplacement::Compile(Handle<String> replacement, int capture_count, substring_index++; } } - return false; + return Just(false); } @@ -489,14 +595,30 @@ MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString( int capture_count = regexp->CaptureCount(); int subject_length = subject->length(); + JSRegExp::Type typeTag = regexp->TypeTag(); + if (typeTag == JSRegExp::IRREGEXP) { + // Ensure the RegExp is compiled so we can access the capture-name map. + if (RegExpImpl::IrregexpPrepare(regexp, subject) == -1) { + DCHECK(isolate->has_pending_exception()); + return isolate->heap()->exception(); + } + } + // CompiledReplacement uses zone allocation. Zone zone(isolate->allocator(), ZONE_NAME); CompiledReplacement compiled_replacement(&zone); - bool simple_replace = - compiled_replacement.Compile(replacement, capture_count, subject_length); + Maybe<bool> maybe_simple_replace = compiled_replacement.Compile( + regexp, replacement, capture_count, subject_length); + if (maybe_simple_replace.IsNothing()) { + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewSyntaxError(MessageTemplate::kRegExpInvalidReplaceString, + replacement)); + } + + const bool simple_replace = maybe_simple_replace.FromJust(); // Shortcut for simple non-regexp global replacements - if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) { + if (typeTag == JSRegExp::ATOM && simple_replace) { if (subject->HasOnlyOneByteChars() && replacement->HasOnlyOneByteChars()) { return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>( isolate, subject, regexp, replacement, last_match_info); @@ -647,7 +769,7 @@ MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString( Heap* heap = isolate->heap(); // The trimming is performed on a newly allocated object, which is on a - // fresly allocated page or on an already swept page. Hence, the sweeper + // freshly allocated page or on an already swept page. Hence, the sweeper // thread can not get confused with the filler creation. No synchronization // needed. // TODO(hpayer): We should shrink the large object page if the size @@ -841,23 +963,28 @@ namespace { class MatchInfoBackedMatch : public String::Match { public: - MatchInfoBackedMatch(Isolate* isolate, Handle<String> subject, + MatchInfoBackedMatch(Isolate* isolate, Handle<JSRegExp> regexp, + Handle<String> subject, Handle<RegExpMatchInfo> match_info) : isolate_(isolate), match_info_(match_info) { subject_ = String::Flatten(subject); + + if (regexp->TypeTag() == JSRegExp::IRREGEXP) { + Object* o = regexp->CaptureNameMap(); + has_named_captures_ = o->IsFixedArray(); + if (has_named_captures_) { + DCHECK(FLAG_harmony_regexp_named_captures); + capture_name_map_ = handle(FixedArray::cast(o)); + } + } else { + has_named_captures_ = false; + } } Handle<String> GetMatch() override { return RegExpUtils::GenericCaptureGetter(isolate_, match_info_, 0, nullptr); } - MaybeHandle<String> GetCapture(int i, bool* capture_exists) override { - Handle<Object> capture_obj = RegExpUtils::GenericCaptureGetter( - isolate_, match_info_, i, capture_exists); - return (*capture_exists) ? Object::ToString(isolate_, capture_obj) - : isolate_->factory()->empty_string(); - } - Handle<String> GetPrefix() override { const int match_start = match_info_->Capture(0); return isolate_->factory()->NewSubString(subject_, 0, match_start); @@ -869,32 +996,90 @@ class MatchInfoBackedMatch : public String::Match { subject_->length()); } + bool HasNamedCaptures() override { return has_named_captures_; } + int CaptureCount() override { return match_info_->NumberOfCaptureRegisters() / 2; } - virtual ~MatchInfoBackedMatch() {} + MaybeHandle<String> GetCapture(int i, bool* capture_exists) override { + Handle<Object> capture_obj = RegExpUtils::GenericCaptureGetter( + isolate_, match_info_, i, capture_exists); + return (*capture_exists) ? Object::ToString(isolate_, capture_obj) + : isolate_->factory()->empty_string(); + } + + MaybeHandle<String> GetNamedCapture(Handle<String> name, + CaptureState* state) override { + DCHECK(has_named_captures_); + const int capture_index = LookupNamedCapture( + [=](String* capture_name) { return capture_name->Equals(*name); }, + *capture_name_map_); + + if (capture_index == -1) { + *state = INVALID; + return name; // Arbitrary string handle. + } + + DCHECK(1 <= capture_index && capture_index <= CaptureCount()); + + bool capture_exists; + Handle<String> capture_value; + ASSIGN_RETURN_ON_EXCEPTION(isolate_, capture_value, + GetCapture(capture_index, &capture_exists), + String); + + if (!capture_exists) { + *state = UNMATCHED; + return isolate_->factory()->empty_string(); + } else { + *state = MATCHED; + return capture_value; + } + } private: Isolate* isolate_; Handle<String> subject_; Handle<RegExpMatchInfo> match_info_; + + bool has_named_captures_; + Handle<FixedArray> capture_name_map_; }; class VectorBackedMatch : public String::Match { public: VectorBackedMatch(Isolate* isolate, Handle<String> subject, Handle<String> match, int match_position, - ZoneVector<Handle<Object>>* captures) + ZoneVector<Handle<Object>>* captures, + Handle<Object> groups_obj) : isolate_(isolate), match_(match), match_position_(match_position), captures_(captures) { subject_ = String::Flatten(subject); + + DCHECK(groups_obj->IsUndefined(isolate) || groups_obj->IsJSReceiver()); + has_named_captures_ = !groups_obj->IsUndefined(isolate); + if (has_named_captures_) groups_obj_ = Handle<JSReceiver>::cast(groups_obj); } Handle<String> GetMatch() override { return match_; } + Handle<String> GetPrefix() override { + return isolate_->factory()->NewSubString(subject_, 0, match_position_); + } + + Handle<String> GetSuffix() override { + const int match_end_position = match_position_ + match_->length(); + return isolate_->factory()->NewSubString(subject_, match_end_position, + subject_->length()); + } + + bool HasNamedCaptures() override { return has_named_captures_; } + + int CaptureCount() override { return static_cast<int>(captures_->size()); } + MaybeHandle<String> GetCapture(int i, bool* capture_exists) override { Handle<Object> capture_obj = captures_->at(i); if (capture_obj->IsUndefined(isolate_)) { @@ -905,19 +1090,30 @@ class VectorBackedMatch : public String::Match { return Object::ToString(isolate_, capture_obj); } - Handle<String> GetPrefix() override { - return isolate_->factory()->NewSubString(subject_, 0, match_position_); - } + MaybeHandle<String> GetNamedCapture(Handle<String> name, + CaptureState* state) override { + DCHECK(has_named_captures_); - Handle<String> GetSuffix() override { - const int match_end_position = match_position_ + match_->length(); - return isolate_->factory()->NewSubString(subject_, match_end_position, - subject_->length()); - } + Maybe<bool> maybe_capture_exists = + JSReceiver::HasProperty(groups_obj_, name); + if (maybe_capture_exists.IsNothing()) return MaybeHandle<String>(); - int CaptureCount() override { return static_cast<int>(captures_->size()); } + if (!maybe_capture_exists.FromJust()) { + *state = INVALID; + return name; // Arbitrary string handle. + } - virtual ~VectorBackedMatch() {} + Handle<Object> capture_obj; + ASSIGN_RETURN_ON_EXCEPTION(isolate_, capture_obj, + Object::GetProperty(groups_obj_, name), String); + if (capture_obj->IsUndefined(isolate_)) { + *state = UNMATCHED; + return isolate_->factory()->empty_string(); + } else { + *state = MATCHED; + return Object::ToString(isolate_, capture_obj); + } + } private: Isolate* isolate_; @@ -925,8 +1121,37 @@ class VectorBackedMatch : public String::Match { Handle<String> match_; const int match_position_; ZoneVector<Handle<Object>>* captures_; + + bool has_named_captures_; + Handle<JSReceiver> groups_obj_; }; +// Create the groups object (see also the RegExp result creation in +// RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo). +Handle<JSObject> ConstructNamedCaptureGroupsObject( + Isolate* isolate, Handle<FixedArray> capture_map, + std::function<Object*(int)> f_get_capture) { + DCHECK(FLAG_harmony_regexp_named_captures); + Handle<JSObject> groups = isolate->factory()->NewJSObjectWithNullProto(); + + const int capture_count = capture_map->length() >> 1; + for (int i = 0; i < capture_count; i++) { + const int name_ix = i * 2; + const int index_ix = i * 2 + 1; + + Handle<String> capture_name(String::cast(capture_map->get(name_ix))); + const int capture_ix = Smi::cast(capture_map->get(index_ix))->value(); + DCHECK(1 <= capture_ix && capture_ix <= capture_count); + + Handle<Object> capture_value(f_get_capture(capture_ix), isolate); + DCHECK(capture_value->IsUndefined(isolate) || capture_value->IsString()); + + JSObject::AddProperty(groups, capture_name, capture_value, NONE); + } + + return groups; +} + // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain // separate last match info. See comment on that function. template <bool has_capture> @@ -934,8 +1159,9 @@ static Object* SearchRegExpMultiple(Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, Handle<RegExpMatchInfo> last_match_array, Handle<JSArray> result_array) { - DCHECK(subject->IsFlat()); + DCHECK(RegExpUtils::IsUnmodifiedRegExp(isolate, regexp)); DCHECK_NE(has_capture, regexp->CaptureCount() == 0); + DCHECK(subject->IsFlat()); int capture_count = regexp->CaptureCount(); int subject_length = subject->length(); @@ -1013,11 +1239,20 @@ static Object* SearchRegExpMultiple(Isolate* isolate, Handle<String> subject, if (has_capture) { // Arguments array to replace function is match, captures, index and - // subject, i.e., 3 + capture count in total. - Handle<FixedArray> elements = - isolate->factory()->NewFixedArray(3 + capture_count); + // subject, i.e., 3 + capture count in total. If the RegExp contains + // named captures, they are also passed as the last argument. + + Handle<Object> maybe_capture_map(regexp->CaptureNameMap(), isolate); + const bool has_named_captures = maybe_capture_map->IsFixedArray(); + DCHECK_IMPLIES(has_named_captures, FLAG_harmony_regexp_named_captures); - elements->set(0, *match); + const int argc = + has_named_captures ? 4 + capture_count : 3 + capture_count; + + Handle<FixedArray> elements = isolate->factory()->NewFixedArray(argc); + int cursor = 0; + + elements->set(cursor++, *match); for (int i = 1; i <= capture_count; i++) { int start = current_match[i * 2]; if (start >= 0) { @@ -1025,14 +1260,25 @@ static Object* SearchRegExpMultiple(Isolate* isolate, Handle<String> subject, DCHECK(start <= end); Handle<String> substring = isolate->factory()->NewSubString(subject, start, end); - elements->set(i, *substring); + elements->set(cursor++, *substring); } else { DCHECK(current_match[i * 2 + 1] < 0); - elements->set(i, isolate->heap()->undefined_value()); + elements->set(cursor++, isolate->heap()->undefined_value()); } } - elements->set(capture_count + 1, Smi::FromInt(match_start)); - elements->set(capture_count + 2, *subject); + + elements->set(cursor++, Smi::FromInt(match_start)); + elements->set(cursor++, *subject); + + if (has_named_captures) { + Handle<FixedArray> capture_map = + Handle<FixedArray>::cast(maybe_capture_map); + Handle<JSObject> groups = ConstructNamedCaptureGroupsObject( + isolate, capture_map, [=](int ix) { return elements->get(ix); }); + elements->set(cursor++, *groups); + } + + DCHECK_EQ(cursor, argc); builder.Add(*isolate->factory()->NewJSArrayWithElements(elements)); } else { builder.Add(*match); @@ -1078,107 +1324,22 @@ static Object* SearchRegExpMultiple(Isolate* isolate, Handle<String> subject, } } -MUST_USE_RESULT MaybeHandle<String> StringReplaceNonGlobalRegExpWithFunction( - Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, - Handle<Object> replace_obj) { - Factory* factory = isolate->factory(); - Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); - - const int flags = regexp->GetFlags(); - - DCHECK(RegExpUtils::IsUnmodifiedRegExp(isolate, regexp)); - DCHECK_EQ(flags & JSRegExp::kGlobal, 0); - - // TODO(jgruber): This should be an easy port to CSA with massive payback. - - const bool sticky = (flags & JSRegExp::kSticky) != 0; - uint32_t last_index = 0; - if (sticky) { - Handle<Object> last_index_obj(regexp->LastIndex(), isolate); - ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj, - Object::ToLength(isolate, last_index_obj), - String); - last_index = PositiveNumberToUint32(*last_index_obj); - - if (static_cast<int>(last_index) > subject->length()) last_index = 0; - } - - Handle<Object> match_indices_obj; - ASSIGN_RETURN_ON_EXCEPTION( - isolate, match_indices_obj, - RegExpImpl::Exec(regexp, subject, last_index, last_match_info), String); - - if (match_indices_obj->IsNull(isolate)) { - if (sticky) regexp->SetLastIndex(0); - return subject; - } - - Handle<RegExpMatchInfo> match_indices = - Handle<RegExpMatchInfo>::cast(match_indices_obj); - - const int index = match_indices->Capture(0); - const int end_of_match = match_indices->Capture(1); - - if (sticky) regexp->SetLastIndex(end_of_match); - - IncrementalStringBuilder builder(isolate); - builder.AppendString(factory->NewSubString(subject, 0, index)); - - // Compute the parameter list consisting of the match, captures, index, - // and subject for the replace function invocation. - // The number of captures plus one for the match. - const int m = match_indices->NumberOfCaptureRegisters() / 2; - - const int argc = m + 2; - ScopedVector<Handle<Object>> argv(argc); - - for (int j = 0; j < m; j++) { - bool ok; - Handle<String> capture = - RegExpUtils::GenericCaptureGetter(isolate, match_indices, j, &ok); - if (ok) { - argv[j] = capture; - } else { - argv[j] = factory->undefined_value(); - } - } - - argv[argc - 2] = handle(Smi::FromInt(index), isolate); - argv[argc - 1] = subject; - - Handle<Object> replacement_obj; - ASSIGN_RETURN_ON_EXCEPTION( - isolate, replacement_obj, - Execution::Call(isolate, replace_obj, factory->undefined_value(), argc, - argv.start()), - String); - - Handle<String> replacement; - ASSIGN_RETURN_ON_EXCEPTION( - isolate, replacement, Object::ToString(isolate, replacement_obj), String); - - builder.AppendString(replacement); - builder.AppendString( - factory->NewSubString(subject, end_of_match, subject->length())); - - return builder.Finish(); -} - // Legacy implementation of RegExp.prototype[Symbol.replace] which // doesn't properly call the underlying exec method. MUST_USE_RESULT MaybeHandle<String> RegExpReplace(Isolate* isolate, Handle<JSRegExp> regexp, Handle<String> string, Handle<Object> replace_obj) { + // Functional fast-paths are dispatched directly by replace builtin. + DCHECK(RegExpUtils::IsUnmodifiedRegExp(isolate, regexp)); + DCHECK(!replace_obj->IsCallable()); + Factory* factory = isolate->factory(); const int flags = regexp->GetFlags(); const bool global = (flags & JSRegExp::kGlobal) != 0; const bool sticky = (flags & JSRegExp::kSticky) != 0; - // Functional fast-paths are dispatched directly by replace builtin. - DCHECK(!replace_obj->IsCallable()); - Handle<String> replace; ASSIGN_RETURN_ON_EXCEPTION(isolate, replace, Object::ToString(isolate, replace_obj), String); @@ -1221,7 +1382,7 @@ MUST_USE_RESULT MaybeHandle<String> RegExpReplace(Isolate* isolate, builder.AppendString(factory->NewSubString(string, 0, start_index)); if (replace->length() > 0) { - MatchInfoBackedMatch m(isolate, string, match_indices); + MatchInfoBackedMatch m(isolate, regexp, string, match_indices); Handle<String> replacement; ASSIGN_RETURN_ON_EXCEPTION(isolate, replacement, String::GetSubstitution(isolate, &m, replace), @@ -1293,56 +1454,118 @@ RUNTIME_FUNCTION(Runtime_RegExpExecMultiple) { RUNTIME_FUNCTION(Runtime_StringReplaceNonGlobalRegExpWithFunction) { HandleScope scope(isolate); DCHECK_EQ(3, args.length()); - CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); - CONVERT_ARG_HANDLE_CHECKED(JSObject, replace, 2); + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, replace_obj, 2); DCHECK(RegExpUtils::IsUnmodifiedRegExp(isolate, regexp)); + DCHECK(replace_obj->map()->is_callable()); - RETURN_RESULT_OR_FAILURE(isolate, StringReplaceNonGlobalRegExpWithFunction( - isolate, subject, regexp, replace)); -} + Factory* factory = isolate->factory(); + Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); -namespace { + const int flags = regexp->GetFlags(); + DCHECK_EQ(flags & JSRegExp::kGlobal, 0); + + // TODO(jgruber): This should be an easy port to CSA with massive payback. + + const bool sticky = (flags & JSRegExp::kSticky) != 0; + uint32_t last_index = 0; + if (sticky) { + Handle<Object> last_index_obj(regexp->LastIndex(), isolate); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, last_index_obj, Object::ToLength(isolate, last_index_obj)); + last_index = PositiveNumberToUint32(*last_index_obj); -// ES##sec-speciesconstructor -// SpeciesConstructor ( O, defaultConstructor ) -MUST_USE_RESULT MaybeHandle<Object> SpeciesConstructor( - Isolate* isolate, Handle<JSReceiver> recv, - Handle<JSFunction> default_ctor) { - Handle<Object> ctor_obj; - ASSIGN_RETURN_ON_EXCEPTION( - isolate, ctor_obj, - JSObject::GetProperty(recv, isolate->factory()->constructor_string()), - Object); + if (static_cast<int>(last_index) > subject->length()) last_index = 0; + } - if (ctor_obj->IsUndefined(isolate)) return default_ctor; + Handle<Object> match_indices_obj; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, match_indices_obj, + RegExpImpl::Exec(regexp, subject, last_index, last_match_info)); - if (!ctor_obj->IsJSReceiver()) { - THROW_NEW_ERROR(isolate, - NewTypeError(MessageTemplate::kConstructorNotReceiver), - Object); + if (match_indices_obj->IsNull(isolate)) { + if (sticky) regexp->SetLastIndex(0); + return *subject; } - Handle<JSReceiver> ctor = Handle<JSReceiver>::cast(ctor_obj); + Handle<RegExpMatchInfo> match_indices = + Handle<RegExpMatchInfo>::cast(match_indices_obj); + + const int index = match_indices->Capture(0); + const int end_of_match = match_indices->Capture(1); - Handle<Object> species; - ASSIGN_RETURN_ON_EXCEPTION( - isolate, species, - JSObject::GetProperty(ctor, isolate->factory()->species_symbol()), - Object); + if (sticky) regexp->SetLastIndex(end_of_match); - if (species->IsNullOrUndefined(isolate)) { - return default_ctor; + IncrementalStringBuilder builder(isolate); + builder.AppendString(factory->NewSubString(subject, 0, index)); + + // Compute the parameter list consisting of the match, captures, index, + // and subject for the replace function invocation. If the RegExp contains + // named captures, they are also passed as the last argument. + + // The number of captures plus one for the match. + const int m = match_indices->NumberOfCaptureRegisters() / 2; + + bool has_named_captures = false; + Handle<FixedArray> capture_map; + if (m > 1) { + // The existence of capture groups implies IRREGEXP kind. + DCHECK_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP); + + Object* maybe_capture_map = regexp->CaptureNameMap(); + if (maybe_capture_map->IsFixedArray()) { + has_named_captures = true; + capture_map = handle(FixedArray::cast(maybe_capture_map)); + } } - if (species->IsConstructor()) return species; + DCHECK_IMPLIES(has_named_captures, FLAG_harmony_regexp_named_captures); + const int argc = has_named_captures ? m + 3 : m + 2; + ScopedVector<Handle<Object>> argv(argc); - THROW_NEW_ERROR( - isolate, NewTypeError(MessageTemplate::kSpeciesNotConstructor), Object); + int cursor = 0; + for (int j = 0; j < m; j++) { + bool ok; + Handle<String> capture = + RegExpUtils::GenericCaptureGetter(isolate, match_indices, j, &ok); + if (ok) { + argv[cursor++] = capture; + } else { + argv[cursor++] = factory->undefined_value(); + } + } + + argv[cursor++] = handle(Smi::FromInt(index), isolate); + argv[cursor++] = subject; + + if (has_named_captures) { + argv[cursor++] = ConstructNamedCaptureGroupsObject( + isolate, capture_map, [&argv](int ix) { return *argv[ix]; }); + } + + DCHECK_EQ(cursor, argc); + + Handle<Object> replacement_obj; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, replacement_obj, + Execution::Call(isolate, replace_obj, factory->undefined_value(), argc, + argv.start())); + + Handle<String> replacement; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, replacement, Object::ToString(isolate, replacement_obj)); + + builder.AppendString(replacement); + builder.AppendString( + factory->NewSubString(subject, end_of_match, subject->length())); + + RETURN_RESULT_OR_FAILURE(isolate, builder.Finish()); } +namespace { + MUST_USE_RESULT MaybeHandle<Object> ToUint32(Isolate* isolate, Handle<Object> object, uint32_t* out) { @@ -1384,7 +1607,7 @@ RUNTIME_FUNCTION(Runtime_RegExpSplit) { Handle<JSFunction> regexp_fun = isolate->regexp_function(); Handle<Object> ctor; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, ctor, SpeciesConstructor(isolate, recv, regexp_fun)); + isolate, ctor, Object::SpeciesConstructor(isolate, recv, regexp_fun)); Handle<Object> flags_obj; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( @@ -1627,14 +1850,14 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) { isolate, position_obj, Object::GetProperty(result, factory->index_string())); - // TODO(jgruber): Extract and correct error handling. Since we can go up to - // 2^53 - 1 (at least for ToLength), we might actually need uint64_t here? ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, position_obj, Object::ToInteger(isolate, position_obj)); const uint32_t position = std::min(PositiveNumberToUint32(*position_obj), length); + // Do not reserve capacity since captures_length is user-controlled. ZoneVector<Handle<Object>> captures(&zone); + for (int n = 0; n < captures_length; n++) { Handle<Object> capture; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( @@ -1647,17 +1870,32 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) { captures.push_back(capture); } + Handle<Object> groups_obj = isolate->factory()->undefined_value(); + if (FLAG_harmony_regexp_named_captures) { + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, groups_obj, + Object::GetProperty(result, factory->groups_string())); + } + + const bool has_named_captures = !groups_obj->IsUndefined(isolate); + DCHECK_IMPLIES(has_named_captures, FLAG_harmony_regexp_named_captures); + Handle<String> replacement; if (functional_replace) { - const int argc = captures_length + 2; + const int argc = + has_named_captures ? captures_length + 3 : captures_length + 2; ScopedVector<Handle<Object>> argv(argc); + int cursor = 0; for (int j = 0; j < captures_length; j++) { - argv[j] = captures[j]; + argv[cursor++] = captures[j]; } - argv[captures_length] = handle(Smi::FromInt(position), isolate); - argv[captures_length + 1] = string; + argv[cursor++] = handle(Smi::FromInt(position), isolate); + argv[cursor++] = string; + if (has_named_captures) argv[cursor++] = groups_obj; + + DCHECK_EQ(cursor, argc); Handle<Object> replacement_obj; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( @@ -1668,7 +1906,13 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) { ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, replacement, Object::ToString(isolate, replacement_obj)); } else { - VectorBackedMatch m(isolate, string, match, position, &captures); + DCHECK(!functional_replace); + if (!groups_obj->IsUndefined(isolate)) { + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, groups_obj, JSReceiver::ToObject(isolate, groups_obj)); + } + VectorBackedMatch m(isolate, string, match, position, &captures, + groups_obj); ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, replacement, String::GetSubstitution(isolate, &m, replace)); } @@ -1692,7 +1936,7 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) { RUNTIME_FUNCTION(Runtime_RegExpExecReThrow) { SealHandleScope shs(isolate); - DCHECK_EQ(4, args.length()); + DCHECK_EQ(0, args.length()); Object* exception = isolate->pending_exception(); isolate->clear_pending_exception(); return isolate->ReThrow(exception); diff --git a/chromium/v8/src/runtime/runtime-strings.cc b/chromium/v8/src/runtime/runtime-strings.cc index 3a435913e35..1ef04ed467f 100644 --- a/chromium/v8/src/runtime/runtime-strings.cc +++ b/chromium/v8/src/runtime/runtime-strings.cc @@ -31,13 +31,21 @@ RUNTIME_FUNCTION(Runtime_GetSubstitution) { : match_(match), prefix_(prefix), suffix_(suffix) {} Handle<String> GetMatch() override { return match_; } + Handle<String> GetPrefix() override { return prefix_; } + Handle<String> GetSuffix() override { return suffix_; } + + int CaptureCount() override { return 0; } + bool HasNamedCaptures() override { return false; } MaybeHandle<String> GetCapture(int i, bool* capture_exists) override { *capture_exists = false; return match_; // Return arbitrary string handle. } - Handle<String> GetPrefix() override { return prefix_; } - Handle<String> GetSuffix() override { return suffix_; } - int CaptureCount() override { return 0; } + MaybeHandle<String> GetNamedCapture(Handle<String> name, + CaptureState* state) override { + UNREACHABLE(); + *state = INVALID; + return MaybeHandle<String>(); + } private: Handle<String> match_, prefix_, suffix_; @@ -191,15 +199,9 @@ RUNTIME_FUNCTION(Runtime_SubString) { RUNTIME_FUNCTION(Runtime_StringAdd) { HandleScope scope(isolate); DCHECK_EQ(2, args.length()); - CONVERT_ARG_HANDLE_CHECKED(Object, obj1, 0); - CONVERT_ARG_HANDLE_CHECKED(Object, obj2, 1); + CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); + CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); isolate->counters()->string_add_runtime()->Increment(); - MaybeHandle<String> maybe_str1(Object::ToString(isolate, obj1)); - MaybeHandle<String> maybe_str2(Object::ToString(isolate, obj2)); - Handle<String> str1; - Handle<String> str2; - maybe_str1.ToHandle(&str1); - maybe_str2.ToHandle(&str2); RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewConsString(str1, str2)); } diff --git a/chromium/v8/src/runtime/runtime-test.cc b/chromium/v8/src/runtime/runtime-test.cc index c6234fcd853..4574b5103e1 100644 --- a/chromium/v8/src/runtime/runtime-test.cc +++ b/chromium/v8/src/runtime/runtime-test.cc @@ -45,7 +45,7 @@ bool IsWasmCompileAllowed(v8::Isolate* isolate, v8::Local<v8::Value> value, // Use the compile controls for instantiation, too bool IsWasmInstantiateAllowed(v8::Isolate* isolate, v8::Local<v8::Value> module_or_bytes, - v8::MaybeLocal<v8::Value> ffi, bool is_async) { + bool is_async) { DCHECK_GT(g_PerIsolateWasmControls.Get().count(isolate), 0); const WasmCompileControls& ctrls = g_PerIsolateWasmControls.Get().at(isolate); if (is_async && ctrls.AllowAnySizeForAsync) return true; @@ -57,6 +57,60 @@ bool IsWasmInstantiateAllowed(v8::Isolate* isolate, return static_cast<uint32_t>(module->GetWasmWireBytes()->Length()) <= ctrls.MaxWasmBufferSize; } + +v8::Local<v8::Value> NewRangeException(v8::Isolate* isolate, + const char* message) { + return v8::Exception::RangeError( + v8::String::NewFromOneByte(isolate, + reinterpret_cast<const uint8_t*>(message), + v8::NewStringType::kNormal) + .ToLocalChecked()); +} + +void ThrowRangeException(v8::Isolate* isolate, const char* message) { + isolate->ThrowException(NewRangeException(isolate, message)); +} + +void RejectPromiseWithRangeError( + const v8::FunctionCallbackInfo<v8::Value>& args, const char* message) { + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope scope(isolate); + + v8::Local<v8::Context> context = isolate->GetCurrentContext(); + v8::Local<v8::Promise::Resolver> resolver; + if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) return; + v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); + return_value.Set(resolver->GetPromise()); + + auto maybe = resolver->Reject(context, NewRangeException(isolate, message)); + CHECK(!maybe.IsNothing()); + return; +} + +bool WasmModuleOverride(const v8::FunctionCallbackInfo<v8::Value>& args) { + if (IsWasmCompileAllowed(args.GetIsolate(), args[0], false)) return false; + ThrowRangeException(args.GetIsolate(), "Sync compile not allowed"); + return true; +} + +bool WasmCompileOverride(const v8::FunctionCallbackInfo<v8::Value>& args) { + if (IsWasmCompileAllowed(args.GetIsolate(), args[0], true)) return false; + RejectPromiseWithRangeError(args, "Async compile not allowed"); + return true; +} + +bool WasmInstanceOverride(const v8::FunctionCallbackInfo<v8::Value>& args) { + if (IsWasmInstantiateAllowed(args.GetIsolate(), args[0], false)) return false; + ThrowRangeException(args.GetIsolate(), "Sync instantiate not allowed"); + return true; +} + +bool WasmInstantiateOverride(const v8::FunctionCallbackInfo<v8::Value>& args) { + if (IsWasmInstantiateAllowed(args.GetIsolate(), args[0], true)) return false; + RejectPromiseWithRangeError(args, "Async instantiate not allowed"); + return true; +} + } // namespace namespace v8 { @@ -71,6 +125,20 @@ RUNTIME_FUNCTION(Runtime_ConstructDouble) { return *isolate->factory()->NewNumber(uint64_to_double(result)); } +RUNTIME_FUNCTION(Runtime_ConstructConsString) { + HandleScope scope(isolate); + DCHECK_EQ(2, args.length()); + CONVERT_ARG_HANDLE_CHECKED(String, left, 0); + CONVERT_ARG_HANDLE_CHECKED(String, right, 1); + + CHECK(left->IsOneByteRepresentation()); + CHECK(right->IsOneByteRepresentation()); + + const bool kIsOneByte = true; + const int length = left->length() + right->length(); + return *isolate->factory()->NewConsString(left, right, length, kIsOneByte); +} + RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) { HandleScope scope(isolate); DCHECK_EQ(1, args.length()); @@ -142,6 +210,25 @@ RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) { isolate->concurrent_recompilation_enabled()); } +RUNTIME_FUNCTION(Runtime_TypeProfile) { + HandleScope scope(isolate); + DCHECK_EQ(1, args.length()); + + if (!FLAG_type_profile) { + return isolate->heap()->undefined_value(); + } + + CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); + if (function->has_feedback_vector()) { + FeedbackVector* vector = function->feedback_vector(); + if (vector->metadata()->HasTypeProfileSlot()) { + FeedbackSlot slot = vector->GetTypeProfileSlot(); + CollectTypeProfileNexus nexus(vector, slot); + return nexus.GetTypeProfile(); + } + } + return *isolate->factory()->NewJSObject(isolate->object_function()); +} RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) { HandleScope scope(isolate); @@ -178,8 +265,7 @@ RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) { function->MarkForOptimization(); - Code* unoptimized = function->shared()->code(); - if (args.length() == 2 && unoptimized->kind() == Code::FUNCTION) { + if (args.length() == 2) { CONVERT_ARG_HANDLE_CHECKED(String, type, 1); if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("concurrent")) && isolate->concurrent_recompilation_enabled()) { @@ -190,53 +276,6 @@ RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) { return isolate->heap()->undefined_value(); } -RUNTIME_FUNCTION(Runtime_InterpretFunctionOnNextCall) { - HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0); - if (!function_object->IsJSFunction()) { - return isolate->heap()->undefined_value(); - } - Handle<JSFunction> function = Handle<JSFunction>::cast(function_object); - - // Do not tier down if we are already on optimized code. Replacing optimized - // code without actual deoptimization can lead to funny bugs. - if (function->code()->kind() != Code::OPTIMIZED_FUNCTION && - function->shared()->HasBytecodeArray()) { - function->ReplaceCode(*isolate->builtins()->InterpreterEntryTrampoline()); - } - return isolate->heap()->undefined_value(); -} - -RUNTIME_FUNCTION(Runtime_BaselineFunctionOnNextCall) { - HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0); - if (!function_object->IsJSFunction()) { - return isolate->heap()->undefined_value(); - } - Handle<JSFunction> function = Handle<JSFunction>::cast(function_object); - - // If function isn't compiled, compile it now. - if (!function->shared()->is_compiled() && - !Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) { - return isolate->heap()->undefined_value(); - } - - // Do not tier down if we are already on optimized code. Replacing optimized - // code without actual deoptimization can lead to funny bugs. - if (function->code()->kind() != Code::OPTIMIZED_FUNCTION && - function->code()->kind() != Code::FUNCTION) { - if (function->shared()->HasBaselineCode()) { - function->ReplaceCode(function->shared()->code()); - } else { - function->MarkForBaseline(); - } - } - - return isolate->heap()->undefined_value(); -} - RUNTIME_FUNCTION(Runtime_OptimizeOsr) { HandleScope scope(isolate); DCHECK(args.length() == 0 || args.length() == 1); @@ -346,6 +385,13 @@ RUNTIME_FUNCTION(Runtime_GetOptimizationCount) { return Smi::FromInt(function->shared()->opt_count()); } +RUNTIME_FUNCTION(Runtime_GetDeoptCount) { + HandleScope scope(isolate); + DCHECK_EQ(1, args.length()); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); + return Smi::FromInt(function->shared()->deopt_count()); +} + static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) { args.GetReturnValue().Set(args.This()); } @@ -478,14 +524,17 @@ RUNTIME_FUNCTION(Runtime_SetWasmCompileControls) { WasmCompileControls& ctrl = (*g_PerIsolateWasmControls.Pointer())[v8_isolate]; ctrl.AllowAnySizeForAsync = allow_async; ctrl.MaxWasmBufferSize = static_cast<uint32_t>(block_size->value()); - isolate->set_allow_wasm_compile_callback(IsWasmCompileAllowed); + v8_isolate->SetWasmModuleCallback(WasmModuleOverride); + v8_isolate->SetWasmCompileCallback(WasmCompileOverride); return isolate->heap()->undefined_value(); } RUNTIME_FUNCTION(Runtime_SetWasmInstantiateControls) { HandleScope scope(isolate); + v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); CHECK(args.length() == 0); - isolate->set_allow_wasm_instantiate_callback(IsWasmInstantiateAllowed); + v8_isolate->SetWasmInstanceCallback(WasmInstanceOverride); + v8_isolate->SetWasmInstantiateCallback(WasmInstantiateOverride); return isolate->heap()->undefined_value(); } @@ -528,6 +577,7 @@ RUNTIME_FUNCTION(Runtime_DebugPrint) { if (args[0]->IsString() && isolate->context() != nullptr) { // If we have a string, assume it's a code "marker" // and print some interesting cpu debugging info. + args[0]->Print(os); JavaScriptFrameIterator it(isolate); JavaScriptFrame* frame = it.frame(); os << "fp = " << static_cast<void*>(frame->fp()) @@ -535,8 +585,8 @@ RUNTIME_FUNCTION(Runtime_DebugPrint) { << ", caller_sp = " << static_cast<void*>(frame->caller_sp()) << ": "; } else { os << "DebugPrint: "; + args[0]->Print(os); } - args[0]->Print(os); if (args[0]->IsHeapObject()) { HeapObject::cast(args[0])->map()->Print(os); } @@ -904,7 +954,7 @@ RUNTIME_FUNCTION(Runtime_ValidateWasmOrphanedInstance) { return isolate->heap()->ToBoolean(true); } -RUNTIME_FUNCTION(Runtime_Verify) { +RUNTIME_FUNCTION(Runtime_HeapObjectVerify) { HandleScope shs(isolate); DCHECK_EQ(1, args.length()); CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); @@ -921,5 +971,41 @@ RUNTIME_FUNCTION(Runtime_Verify) { return isolate->heap()->ToBoolean(true); } +RUNTIME_FUNCTION(Runtime_WasmNumInterpretedCalls) { + DCHECK_EQ(1, args.length()); + HandleScope scope(isolate); + CONVERT_ARG_HANDLE_CHECKED(JSObject, instance_obj, 0); + CHECK(WasmInstanceObject::IsWasmInstanceObject(*instance_obj)); + Handle<WasmInstanceObject> instance = + Handle<WasmInstanceObject>::cast(instance_obj); + if (!instance->has_debug_info()) return 0; + uint64_t num = instance->debug_info()->NumInterpretedCalls(); + return *isolate->factory()->NewNumberFromSize(static_cast<size_t>(num)); +} + +RUNTIME_FUNCTION(Runtime_RedirectToWasmInterpreter) { + DCHECK_EQ(2, args.length()); + HandleScope scope(isolate); + CONVERT_ARG_HANDLE_CHECKED(JSObject, instance_obj, 0); + CONVERT_SMI_ARG_CHECKED(function_index, 1); + CHECK(WasmInstanceObject::IsWasmInstanceObject(*instance_obj)); + Handle<WasmInstanceObject> instance = + Handle<WasmInstanceObject>::cast(instance_obj); + Handle<WasmDebugInfo> debug_info = + WasmInstanceObject::GetOrCreateDebugInfo(instance); + WasmDebugInfo::RedirectToInterpreter(debug_info, + Vector<int>(&function_index, 1)); + return isolate->heap()->undefined_value(); +} + +RUNTIME_FUNCTION(Runtime_IncrementWaitCount) { + isolate->IncrementWaitCountForTesting(); + return isolate->heap()->undefined_value(); +} + +RUNTIME_FUNCTION(Runtime_DecrementWaitCount) { + isolate->DecrementWaitCountForTesting(); + return isolate->heap()->undefined_value(); +} } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/runtime/runtime-typedarray.cc b/chromium/v8/src/runtime/runtime-typedarray.cc index 4ca7bbb009f..eeaa40e5ea6 100644 --- a/chromium/v8/src/runtime/runtime-typedarray.cc +++ b/chromium/v8/src/runtime/runtime-typedarray.cc @@ -5,6 +5,7 @@ #include "src/runtime/runtime-utils.h" #include "src/arguments.h" +#include "src/elements.h" #include "src/factory.h" #include "src/messages.h" #include "src/objects-inl.h" @@ -21,43 +22,18 @@ RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) { } -RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) { +RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) { HandleScope scope(isolate); - DCHECK_EQ(4, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0); - CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(first, 2); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(new_length, 3); - - if (source->was_neutered() || target->was_neutered()) { + DCHECK_EQ(1, args.length()); + Handle<Object> argument = args.at(0); + // This runtime function is exposed in ClusterFuzz and as such has to + // support arbitrary arguments. + if (!argument->IsJSArrayBuffer()) { THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kDetachedOperation, - isolate->factory()->NewStringFromAsciiChecked( - "ArrayBuffer.prototype.slice"))); + isolate, NewTypeError(MessageTemplate::kNotTypedArray)); } + Handle<JSArrayBuffer> array_buffer = Handle<JSArrayBuffer>::cast(argument); - CHECK(!source.is_identical_to(target)); - size_t start = 0, target_length = 0; - CHECK(TryNumberToSize(*first, &start)); - CHECK(TryNumberToSize(*new_length, &target_length)); - CHECK(NumberToSize(target->byte_length()) >= target_length); - - if (target_length == 0) return isolate->heap()->undefined_value(); - - size_t source_byte_length = NumberToSize(source->byte_length()); - CHECK(start <= source_byte_length); - CHECK(source_byte_length - start >= target_length); - uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store()); - uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store()); - CopyBytes(target_data, source_data + start, target_length); - return isolate->heap()->undefined_value(); -} - - -RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) { - HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0); if (array_buffer->backing_store() == NULL) { CHECK(Smi::kZero == array_buffer->byte_length()); return isolate->heap()->undefined_value(); @@ -74,203 +50,6 @@ RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) { return isolate->heap()->undefined_value(); } - -void Runtime::ArrayIdToTypeAndSize(int arrayId, ExternalArrayType* array_type, - ElementsKind* fixed_elements_kind, - size_t* element_size) { - switch (arrayId) { -#define ARRAY_ID_CASE(Type, type, TYPE, ctype, size) \ - case ARRAY_ID_##TYPE: \ - *array_type = kExternal##Type##Array; \ - *fixed_elements_kind = TYPE##_ELEMENTS; \ - *element_size = size; \ - break; - - TYPED_ARRAYS(ARRAY_ID_CASE) -#undef ARRAY_ID_CASE - - default: - UNREACHABLE(); - } -} - - -RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) { - HandleScope scope(isolate); - DCHECK_EQ(6, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); - CONVERT_SMI_ARG_CHECKED(arrayId, 1); - CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4); - CONVERT_BOOLEAN_ARG_CHECKED(initialize, 5); - - CHECK(arrayId >= Runtime::ARRAY_ID_FIRST && - arrayId <= Runtime::ARRAY_ID_LAST); - - ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization. - size_t element_size = 1; // Bogus initialization. - ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization. - Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &fixed_elements_kind, - &element_size); - CHECK(holder->map()->elements_kind() == fixed_elements_kind); - - size_t byte_offset = 0; - size_t byte_length = 0; - CHECK(TryNumberToSize(*byte_offset_object, &byte_offset)); - CHECK(TryNumberToSize(*byte_length_object, &byte_length)); - - if (maybe_buffer->IsJSArrayBuffer()) { - Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer); - size_t array_buffer_byte_length = NumberToSize(buffer->byte_length()); - CHECK(byte_offset <= array_buffer_byte_length); - CHECK(array_buffer_byte_length - byte_offset >= byte_length); - } else { - CHECK(maybe_buffer->IsNull(isolate)); - } - - CHECK(byte_length % element_size == 0); - size_t length = byte_length / element_size; - - if (length > static_cast<unsigned>(Smi::kMaxValue)) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewRangeError(MessageTemplate::kInvalidTypedArrayLength)); - } - - // All checks are done, now we can modify objects. - - DCHECK_EQ(v8::ArrayBufferView::kInternalFieldCount, - holder->GetInternalFieldCount()); - for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { - holder->SetInternalField(i, Smi::kZero); - } - Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length); - holder->set_length(*length_obj); - holder->set_byte_offset(*byte_offset_object); - holder->set_byte_length(*byte_length_object); - - if (!maybe_buffer->IsNull(isolate)) { - Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer); - holder->set_buffer(*buffer); - - Handle<FixedTypedArrayBase> elements = - isolate->factory()->NewFixedTypedArrayWithExternalPointer( - static_cast<int>(length), array_type, - static_cast<uint8_t*>(buffer->backing_store()) + byte_offset); - holder->set_elements(*elements); - } else { - Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); - JSArrayBuffer::Setup(buffer, isolate, true, NULL, byte_length, - SharedFlag::kNotShared); - holder->set_buffer(*buffer); - Handle<FixedTypedArrayBase> elements = - isolate->factory()->NewFixedTypedArray(static_cast<int>(length), - array_type, initialize); - holder->set_elements(*elements); - } - return isolate->heap()->undefined_value(); -} - - -// Initializes a typed array from an array-like object. -// If an array-like object happens to be a typed array of the same type, -// initializes backing store using memove. -// -// Returns true if backing store was initialized or false otherwise. -RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) { - HandleScope scope(isolate); - DCHECK_EQ(4, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); - CONVERT_SMI_ARG_CHECKED(arrayId, 1); - CONVERT_ARG_HANDLE_CHECKED(Object, source, 2); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3); - - CHECK(arrayId >= Runtime::ARRAY_ID_FIRST && - arrayId <= Runtime::ARRAY_ID_LAST); - - ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization. - size_t element_size = 1; // Bogus initialization. - ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization. - Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &fixed_elements_kind, - &element_size); - - CHECK(holder->map()->elements_kind() == fixed_elements_kind); - - Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); - size_t length = 0; - if (source->IsJSTypedArray() && - JSTypedArray::cast(*source)->type() == array_type) { - length = JSTypedArray::cast(*source)->length_value(); - } else { - CHECK(TryNumberToSize(*length_obj, &length)); - } - - if ((length > static_cast<unsigned>(Smi::kMaxValue)) || - (length > (kMaxInt / element_size))) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewRangeError(MessageTemplate::kInvalidTypedArrayLength)); - } - size_t byte_length = length * element_size; - - DCHECK_EQ(v8::ArrayBufferView::kInternalFieldCount, - holder->GetInternalFieldCount()); - for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { - holder->SetInternalField(i, Smi::kZero); - } - - // NOTE: not initializing backing store. - // We assume that the caller of this function will initialize holder - // with the loop - // for(i = 0; i < length; i++) { holder[i] = source[i]; } - // We assume that the caller of this function is always a typed array - // constructor. - // If source is a typed array, this loop will always run to completion, - // so we are sure that the backing store will be initialized. - // Otherwise, the indexing operation might throw, so the loop will not - // run to completion and the typed array might remain partly initialized. - // However we further assume that the caller of this function is a typed array - // constructor, and the exception will propagate out of the constructor, - // therefore uninitialized memory will not be accessible by a user program. - // - // TODO(dslomov): revise this once we support subclassing. - - if (!JSArrayBuffer::SetupAllocatingData(buffer, isolate, byte_length, - false)) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength)); - } - - holder->set_buffer(*buffer); - holder->set_byte_offset(Smi::kZero); - Handle<Object> byte_length_obj( - isolate->factory()->NewNumberFromSize(byte_length)); - holder->set_byte_length(*byte_length_obj); - length_obj = isolate->factory()->NewNumberFromSize(length); - holder->set_length(*length_obj); - - Handle<FixedTypedArrayBase> elements = - isolate->factory()->NewFixedTypedArrayWithExternalPointer( - static_cast<int>(length), array_type, - static_cast<uint8_t*>(buffer->backing_store())); - holder->set_elements(*elements); - - if (source->IsJSTypedArray()) { - Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source)); - - if (typed_array->type() == holder->type()) { - uint8_t* backing_store = - static_cast<uint8_t*>(typed_array->GetBuffer()->backing_store()); - size_t source_byte_offset = NumberToSize(typed_array->byte_offset()); - memcpy(buffer->backing_store(), backing_store + source_byte_offset, - byte_length); - return isolate->heap()->true_value(); - } - } - - return isolate->heap()->false_value(); -} - - #define BUFFER_VIEW_GETTER(Type, getter, accessor) \ RUNTIME_FUNCTION(Runtime_##Type##Get##getter) { \ HandleScope scope(isolate); \ @@ -316,8 +95,9 @@ RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) { isolate, NewTypeError(MessageTemplate::kNotTypedArray)); } - if (!args[1]->IsJSTypedArray()) + if (!args[1]->IsJSTypedArray()) { return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY); + } CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1); diff --git a/chromium/v8/src/runtime/runtime-wasm.cc b/chromium/v8/src/runtime/runtime-wasm.cc index 9f125c1345e..090d5b4a40e 100644 --- a/chromium/v8/src/runtime/runtime-wasm.cc +++ b/chromium/v8/src/runtime/runtime-wasm.cc @@ -12,6 +12,8 @@ #include "src/factory.h" #include "src/frames-inl.h" #include "src/objects-inl.h" +#include "src/objects/frame-array-inl.h" +#include "src/trap-handler/trap-handler.h" #include "src/v8memory.h" #include "src/wasm/wasm-module.h" #include "src/wasm/wasm-objects.h" @@ -43,10 +45,8 @@ RUNTIME_FUNCTION(Runtime_WasmMemorySize) { HandleScope scope(isolate); DCHECK_EQ(0, args.length()); - Handle<WasmInstanceObject> instance(GetWasmInstanceOnStackTop(isolate), - isolate); - return *isolate->factory()->NewNumberFromInt( - wasm::GetInstanceMemorySize(isolate, instance)); + int32_t mem_size = GetWasmInstanceOnStackTop(isolate)->GetMemorySize(); + return *isolate->factory()->NewNumberFromInt(mem_size); } RUNTIME_FUNCTION(Runtime_WasmGrowMemory) { @@ -61,7 +61,7 @@ RUNTIME_FUNCTION(Runtime_WasmGrowMemory) { isolate->set_context(instance->compiled_module()->ptr_to_native_context()); return *isolate->factory()->NewNumberFromInt( - wasm::GrowMemory(isolate, instance, delta_pages)); + WasmInstanceObject::GrowMemory(isolate, instance, delta_pages)); } Object* ThrowRuntimeError(Isolate* isolate, int message_id, int byte_offset, @@ -103,19 +103,10 @@ Object* ThrowRuntimeError(Isolate* isolate, int message_id, int byte_offset, Handle<FixedArray> stack_elements( FixedArray::cast(JSArray::cast(*detailed_stack_trace_obj)->elements())); DCHECK_GE(stack_elements->length(), 1); - Handle<JSObject> top_frame(JSObject::cast(stack_elements->get(0))); - Handle<String> wasm_offset_key = - isolate->factory()->InternalizeOneByteString( - STATIC_CHAR_VECTOR("column")); - LookupIterator it(top_frame, wasm_offset_key, top_frame, - LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); - if (it.IsFound()) { - DCHECK(JSReceiver::GetDataProperty(&it)->IsSmi()); - // Make column number 1-based here. - Maybe<bool> data_set = JSReceiver::SetDataProperty( - &it, handle(Smi::FromInt(byte_offset + 1), isolate)); - DCHECK(data_set.IsJust() && data_set.FromJust() == true); - USE(data_set); + Handle<StackFrameInfo> top_frame( + StackFrameInfo::cast(stack_elements->get(0))); + if (top_frame->column_number()) { + top_frame->set_column_number(byte_offset + 1); } } @@ -135,6 +126,14 @@ RUNTIME_FUNCTION(Runtime_ThrowWasmError) { return ThrowRuntimeError(isolate, message_id, byte_offset, true); } +RUNTIME_FUNCTION(Runtime_ThrowWasmStackOverflow) { + SealHandleScope shs(isolate); + DCHECK_LE(0, args.length()); + DCHECK_NULL(isolate->context()); + isolate->set_context(GetWasmContextOnStackTop(isolate)); + return isolate->StackOverflow(); +} + RUNTIME_FUNCTION(Runtime_WasmThrowTypeError) { HandleScope scope(isolate); DCHECK_EQ(0, args.length()); @@ -168,6 +167,16 @@ RUNTIME_FUNCTION(Runtime_WasmGetCaughtExceptionValue) { return exception; } +RUNTIME_FUNCTION(Runtime_SetThreadInWasm) { + trap_handler::SetThreadInWasm(); + return isolate->heap()->undefined_value(); +} + +RUNTIME_FUNCTION(Runtime_ClearThreadInWasm) { + trap_handler::ClearThreadInWasm(); + return isolate->heap()->undefined_value(); +} + RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) { DCHECK_EQ(3, args.length()); HandleScope scope(isolate); @@ -189,13 +198,38 @@ RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) { DCHECK_NULL(isolate->context()); isolate->set_context(instance->compiled_module()->ptr_to_native_context()); - instance->debug_info()->RunInterpreter(func_index, arg_buffer); + // Find the frame pointer of the interpreter entry. + Address frame_pointer = 0; + { + StackFrameIterator it(isolate, isolate->thread_local_top()); + // On top: C entry stub. + DCHECK_EQ(StackFrame::EXIT, it.frame()->type()); + it.Advance(); + // Next: the wasm interpreter entry. + DCHECK_EQ(StackFrame::WASM_INTERPRETER_ENTRY, it.frame()->type()); + frame_pointer = it.frame()->fp(); + } + + bool success = instance->debug_info()->RunInterpreter(frame_pointer, + func_index, arg_buffer); + + if (!success) { + DCHECK(isolate->has_pending_exception()); + return isolate->heap()->exception(); + } return isolate->heap()->undefined_value(); } RUNTIME_FUNCTION(Runtime_WasmStackGuard) { SealHandleScope shs(isolate); DCHECK_EQ(0, args.length()); + DCHECK(!trap_handler::UseTrapHandler() || trap_handler::IsThreadInWasm()); + + struct ClearAndRestoreThreadInWasm { + ClearAndRestoreThreadInWasm() { trap_handler::ClearThreadInWasm(); } + + ~ClearAndRestoreThreadInWasm() { trap_handler::SetThreadInWasm(); } + } restore_thread_in_wasm; // Set the current isolate's context. DCHECK_NULL(isolate->context()); @@ -208,5 +242,12 @@ RUNTIME_FUNCTION(Runtime_WasmStackGuard) { return isolate->stack_guard()->HandleInterrupts(); } +RUNTIME_FUNCTION(Runtime_WasmCompileLazy) { + DCHECK(args.length() == 0); + HandleScope scope(isolate); + + return *wasm::CompileLazy(isolate); +} + } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/runtime/runtime.h b/chromium/v8/src/runtime/runtime.h index 6c5a039d672..eb5f09db9b9 100644 --- a/chromium/v8/src/runtime/runtime.h +++ b/chromium/v8/src/runtime/runtime.h @@ -37,7 +37,6 @@ namespace internal { // are specified by inline comments #define FOR_EACH_INTRINSIC_ARRAY(F) \ - F(FinishArrayPrototypeSetup, 1, 1) \ F(SpecialArrayFunctions, 0, 1) \ F(TransitionElementsKind, 2, 1) \ F(RemoveArrayHoles, 2, 1) \ @@ -63,16 +62,13 @@ namespace internal { F(ThrowNotIntegerSharedTypedArrayError, 1, 1) \ F(ThrowNotInt32SharedTypedArrayError, 1, 1) \ F(ThrowInvalidAtomicAccessIndexError, 0, 1) \ + F(AtomicsExchange, 3, 1) \ F(AtomicsCompareExchange, 4, 1) \ F(AtomicsAdd, 3, 1) \ F(AtomicsSub, 3, 1) \ F(AtomicsAnd, 3, 1) \ F(AtomicsOr, 3, 1) \ F(AtomicsXor, 3, 1) \ - F(AtomicsExchange, 3, 1) \ - F(AtomicsIsLockFree, 1, 1) \ - F(AtomicsWait, 4, 1) \ - F(AtomicsWake, 3, 1) \ F(AtomicsNumWaitersForTesting, 2, 1) \ F(SetAllowAtomicsWait, 1, 1) @@ -81,6 +77,7 @@ namespace internal { F(ThrowConstructorNonCallableError, 1, 1) \ F(ThrowStaticPrototypeError, 0, 1) \ F(ThrowSuperAlreadyCalledError, 0, 1) \ + F(ThrowSuperNotCalled, 0, 1) \ F(ThrowNotSuperConstructor, 2, 1) \ F(HomeObjectSymbol, 0, 1) \ F(DefineClass, 4, 1) \ @@ -125,7 +122,6 @@ namespace internal { #define FOR_EACH_INTRINSIC_COMPILER(F) \ F(CompileLazy, 1, 1) \ - F(CompileBaseline, 1, 1) \ F(CompileOptimized_Concurrent, 1, 1) \ F(CompileOptimized_NotConcurrent, 1, 1) \ F(NotifyStubFailure, 0, 1) \ @@ -241,15 +237,18 @@ namespace internal { F(IsFunction, 1, 1) \ F(FunctionToString, 1, 1) -#define FOR_EACH_INTRINSIC_GENERATOR(F) \ - F(CreateJSGeneratorObject, 2, 1) \ - F(GeneratorClose, 1, 1) \ - F(GeneratorGetFunction, 1, 1) \ - F(GeneratorGetReceiver, 1, 1) \ - F(GeneratorGetContext, 1, 1) \ - F(GeneratorGetInputOrDebugPos, 1, 1) \ - F(GeneratorGetContinuation, 1, 1) \ - F(GeneratorGetSourcePosition, 1, 1) \ +#define FOR_EACH_INTRINSIC_GENERATOR(F) \ + F(CreateJSGeneratorObject, 2, 1) \ + F(GeneratorClose, 1, 1) \ + F(GeneratorGetFunction, 1, 1) \ + F(GeneratorGetReceiver, 1, 1) \ + F(GeneratorGetContext, 1, 1) \ + F(GeneratorGetInputOrDebugPos, 1, 1) \ + F(AsyncGeneratorGetAwaitInputOrDebugPos, 1, 1) \ + F(AsyncGeneratorResolve, 3, 1) \ + F(AsyncGeneratorReject, 2, 1) \ + F(GeneratorGetContinuation, 1, 1) \ + F(GeneratorGetSourcePosition, 1, 1) \ F(GeneratorGetResumeMode, 1, 1) #ifdef V8_I18N_SUPPORT @@ -266,9 +265,9 @@ namespace internal { F(InternalDateFormatToParts, 2, 1) \ F(CreateNumberFormat, 3, 1) \ F(InternalNumberFormat, 2, 1) \ + F(CurrencyDigits, 1, 1) \ F(CreateCollator, 3, 1) \ F(InternalCompare, 3, 1) \ - F(StringNormalize, 2, 1) \ F(CreateBreakIterator, 3, 1) \ F(BreakIteratorAdoptText, 2, 1) \ F(BreakIteratorFirst, 1, 1) \ @@ -317,12 +316,14 @@ namespace internal { F(ThrowIncompatibleMethodReceiver, 2, 1) \ F(ThrowInvalidHint, 1, 1) \ F(ThrowInvalidStringLength, 0, 1) \ + F(ThrowInvalidTypedArrayAlignment, 2, 1) \ F(ThrowIteratorResultNotAnObject, 1, 1) \ F(ThrowSymbolIteratorInvalid, 0, 1) \ F(ThrowNonCallableInInstanceOfCheck, 0, 1) \ F(ThrowNonObjectInInstanceOfCheck, 0, 1) \ F(ThrowNotConstructor, 1, 1) \ F(ThrowNotGeneric, 1, 1) \ + F(ThrowRangeError, -1 /* >= 1 */, 1) \ F(ThrowReferenceError, 1, 1) \ F(ThrowStackOverflow, 0, 1) \ F(ThrowSymbolAsyncIteratorInvalid, 0, 1) \ @@ -355,7 +356,7 @@ namespace internal { #define FOR_EACH_INTRINSIC_MATHS(F) F(GenerateRandomNumbers, 0, 1) #define FOR_EACH_INTRINSIC_MODULE(F) \ - F(DynamicImportCall, 1, 1) \ + F(DynamicImportCall, 2, 1) \ F(GetModuleNamespace, 1, 1) \ F(LoadModuleVariable, 1, 1) \ F(StoreModuleVariable, 2, 1) @@ -371,11 +372,11 @@ namespace internal { F(SmiLexicographicCompare, 2, 1) \ F(MaxSmi, 0, 1) \ F(IsSmi, 1, 1) \ - F(GetRootNaN, 0, 1) \ F(GetHoleNaNUpper, 0, 1) \ F(GetHoleNaNLower, 0, 1) #define FOR_EACH_INTRINSIC_OBJECT(F) \ + F(AddDictionaryProperty, 3, 1) \ F(GetPrototype, 1, 1) \ F(ObjectHasOwnProperty, 2, 1) \ F(ObjectCreate, 2, 1) \ @@ -401,6 +402,7 @@ namespace internal { F(IsJSGlobalProxy, 1, 1) \ F(DefineAccessorPropertyUnchecked, 5, 1) \ F(DefineDataPropertyInLiteral, 6, 1) \ + F(CollectTypeProfile, 3, 1) \ F(GetDataProperty, 2, 1) \ F(GetConstructorName, 1, 1) \ F(HasFastPackedElements, 1, 1) \ @@ -426,7 +428,8 @@ namespace internal { F(CreateIterResultObject, 2, 1) \ F(CreateKeyValueArray, 2, 1) \ F(IsAccessCheckNeeded, 1, 1) \ - F(CreateDataProperty, 3, 1) + F(CreateDataProperty, 3, 1) \ + F(IterableToListCanBeElided, 1, 1) #define FOR_EACH_INTRINSIC_OPERATORS(F) \ F(Multiply, 2, 1) \ @@ -463,7 +466,9 @@ namespace internal { F(PromiseRevokeReject, 1, 1) \ F(PromiseResult, 1, 1) \ F(PromiseStatus, 1, 1) \ - F(ReportPromiseReject, 2, 1) + F(ReportPromiseReject, 2, 1) \ + F(IncrementWaitCount, 0, 1) \ + F(DecrementWaitCount, 0, 1) #define FOR_EACH_INTRINSIC_PROXY(F) \ F(IsJSProxy, 1, 1) \ @@ -478,7 +483,7 @@ namespace internal { F(RegExpCreate, 1, 1) \ F(RegExpExec, 4, 1) \ F(RegExpExecMultiple, 4, 1) \ - F(RegExpExecReThrow, 4, 1) \ + F(RegExpExecReThrow, 0, 1) \ F(RegExpInitializeAndCompile, 3, 1) \ F(RegExpInternalReplace, 3, 1) \ F(RegExpReplace, 3, 1) \ @@ -548,18 +553,19 @@ namespace internal { #define FOR_EACH_INTRINSIC_TEST(F) \ F(ConstructDouble, 2, 1) \ + F(ConstructConsString, 2, 1) \ F(DeoptimizeFunction, 1, 1) \ F(DeoptimizeNow, 0, 1) \ F(RunningInSimulator, 0, 1) \ F(IsConcurrentRecompilationSupported, 0, 1) \ F(OptimizeFunctionOnNextCall, -1, 1) \ - F(InterpretFunctionOnNextCall, 1, 1) \ - F(BaselineFunctionOnNextCall, 1, 1) \ + F(TypeProfile, 1, 1) \ F(OptimizeOsr, -1, 1) \ F(NeverOptimizeFunction, 1, 1) \ F(GetOptimizationStatus, -1, 1) \ F(UnblockConcurrentRecompilation, 0, 1) \ F(GetOptimizationCount, 1, 1) \ + F(GetDeoptCount, 1, 1) \ F(GetUndetectable, 0, 1) \ F(GetCallable, 0, 1) \ F(ClearFunctionFeedback, 1, 1) \ @@ -611,14 +617,13 @@ namespace internal { F(ValidateWasmOrphanedInstance, 1, 1) \ F(SetWasmCompileControls, 2, 1) \ F(SetWasmInstantiateControls, 0, 1) \ - F(Verify, 1, 1) + F(HeapObjectVerify, 1, 1) \ + F(WasmNumInterpretedCalls, 1, 1) \ + F(RedirectToWasmInterpreter, 2, 1) #define FOR_EACH_INTRINSIC_TYPEDARRAY(F) \ F(ArrayBufferGetByteLength, 1, 1) \ - F(ArrayBufferSliceImpl, 4, 1) \ F(ArrayBufferNeuter, 1, 1) \ - F(TypedArrayInitialize, 6, 1) \ - F(TypedArrayInitializeFromArrayLike, 4, 1) \ F(ArrayBufferViewGetByteLength, 1, 1) \ F(ArrayBufferViewGetByteOffset, 1, 1) \ F(TypedArrayGetLength, 1, 1) \ @@ -636,11 +641,15 @@ namespace internal { F(WasmMemorySize, 0, 1) \ F(ThrowWasmError, 2, 1) \ F(ThrowWasmErrorFromTrapIf, 1, 1) \ + F(ThrowWasmStackOverflow, 0, 1) \ F(WasmThrowTypeError, 0, 1) \ F(WasmThrow, 2, 1) \ F(WasmGetCaughtExceptionValue, 1, 1) \ F(WasmRunInterpreter, 3, 1) \ - F(WasmStackGuard, 0, 1) + F(WasmStackGuard, 0, 1) \ + F(SetThreadInWasm, 0, 1) \ + F(ClearThreadInWasm, 0, 1) \ + F(WasmCompileLazy, 0, 1) #define FOR_EACH_INTRINSIC_RETURN_PAIR(F) \ F(LoadLookupSlotForCall, 1, 2) @@ -663,7 +672,6 @@ namespace internal { F(LoadGlobalIC_Slow, 3, 1) \ F(LoadIC_Miss, 4, 1) \ F(LoadPropertyWithInterceptor, 5, 1) \ - F(LoadPropertyWithInterceptorOnly, 3, 1) \ F(StoreCallbackProperty, 6, 1) \ F(StoreIC_Miss, 5, 1) \ F(StorePropertyWithInterceptor, 5, 1) \ @@ -777,27 +785,8 @@ class Runtime : public AllStatic { Isolate* isolate, Handle<Object> object, Handle<Object> key, bool* is_found_out = nullptr); - enum TypedArrayId { - // arrayIds below should be synchronized with typedarray.js natives. - ARRAY_ID_UINT8 = 1, - ARRAY_ID_INT8 = 2, - ARRAY_ID_UINT16 = 3, - ARRAY_ID_INT16 = 4, - ARRAY_ID_UINT32 = 5, - ARRAY_ID_INT32 = 6, - ARRAY_ID_FLOAT32 = 7, - ARRAY_ID_FLOAT64 = 8, - ARRAY_ID_UINT8_CLAMPED = 9, - ARRAY_ID_FIRST = ARRAY_ID_UINT8, - ARRAY_ID_LAST = ARRAY_ID_UINT8_CLAMPED - }; - - static void ArrayIdToTypeAndSize(int array_id, ExternalArrayType* type, - ElementsKind* fixed_elements_kind, - size_t* element_size); - - static MaybeHandle<JSArray> GetInternalProperties(Isolate* isolate, - Handle<Object>); + MUST_USE_RESULT static MaybeHandle<JSArray> GetInternalProperties( + Isolate* isolate, Handle<Object>); }; |