diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/v8/src/builtins | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/v8/src/builtins')
52 files changed, 2276 insertions, 2687 deletions
diff --git a/chromium/v8/src/builtins/aggregate-error.tq b/chromium/v8/src/builtins/aggregate-error.tq new file mode 100644 index 00000000000..0f4a47b3e73 --- /dev/null +++ b/chromium/v8/src/builtins/aggregate-error.tq @@ -0,0 +1,49 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include 'src/objects/js-objects.h' + +namespace error { + +transitioning javascript builtin AggregateErrorConstructor( + js-implicit context: NativeContext, target: JSFunction, + newTarget: JSAny)(...arguments): JSAny { + // This function is implementing the spec as suggested by + // https://github.com/tc39/proposal-promise-any/pull/59 . FIXME(marja): + // change this if the PR is declined, otherwise remove the comment. + + // 1. If NewTarget is undefined, let newTarget be the active function + // object, else let newTarget be NewTarget. + // 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, + // "%AggregateError.prototype%", « [[ErrorData]], [[AggregateErrors]] »). + // 3. If _message_ is not _undefined_, then + // a. Let msg be ? ToString(_message_). + // b. Let msgDesc be the PropertyDescriptor { [[Value]]: _msg_, + // [[Writable]]: *true*, [[Enumerable]]: *false*, [[Configurable]]: *true* + // c. Perform ! DefinePropertyOrThrow(_O_, *"message"*, _msgDesc_). + const message: JSAny = arguments[1]; + const obj: JSObject = + ConstructAggregateErrorHelper(context, target, newTarget, message); + + // 4. Let errorsList be ? IterableToList(errors). + const errors: JSAny = arguments[0]; + const errorsList = iterator::IterableToListWithSymbolLookup(errors); + + // 5. Perform ! DefinePropertyOrThrow(_O_, `"errors"`, Property Descriptor { + // [[Configurable]]: *true*, [[Enumerable]]: *false*, [[Writable]]: *true*, + // [[Value]]: ! CreateArrayFromList(_errorsList_) }). + SetOwnPropertyIgnoreAttributes( + obj, ErrorsStringConstant(), errorsList, + SmiConstant(PropertyAttributes::DONT_ENUM)); + + // 6. Return O. + return obj; +} + +extern transitioning runtime ConstructAggregateErrorHelper( + Context, JSFunction, JSAny, Object): JSObject; + +extern transitioning runtime ConstructInternalAggregateErrorHelper( + Context, Object): JSObject; +} diff --git a/chromium/v8/src/builtins/array-join.tq b/chromium/v8/src/builtins/array-join.tq index 08d0cbf894b..7bf74e4e317 100644 --- a/chromium/v8/src/builtins/array-join.tq +++ b/chromium/v8/src/builtins/array-join.tq @@ -296,7 +296,7 @@ transitioning macro ArrayJoinImpl<T: type>(implicit context: Context)( } case (obj: JSAny): { if (IsNullOrUndefined(obj)) continue; - next = ToString(context, obj); + next = string::ToString(context, obj); } } } @@ -418,7 +418,7 @@ macro LoadJoinStack(implicit context: Context)(): FixedArray const stack: HeapObject = UnsafeCast<HeapObject>( nativeContext[NativeContextSlot::ARRAY_JOIN_STACK_INDEX]); if (stack == Undefined) goto IfUninitialized; - assert(IsFixedArray(stack)); + assert(Is<FixedArray>(stack)); return UnsafeCast<FixedArray>(stack); } diff --git a/chromium/v8/src/builtins/array-slice.tq b/chromium/v8/src/builtins/array-slice.tq index 147dae6f72f..97026586adf 100644 --- a/chromium/v8/src/builtins/array-slice.tq +++ b/chromium/v8/src/builtins/array-slice.tq @@ -36,21 +36,18 @@ macro HandleFastAliasedSloppyArgumentsSlice( const sloppyElements: SloppyArgumentsElements = Cast<SloppyArgumentsElements>(args.elements) otherwise Bailout; - const sloppyElementsLength: Smi = sloppyElements.length; - const parameterMapLength: Smi = - sloppyElementsLength - kSloppyArgumentsParameterMapStart; + const parameterMapLength: Smi = sloppyElements.length; // Check to make sure that the extraction will not access outside the // defined arguments const end: Smi = start + count; const unmappedElements: FixedArray = - Cast<FixedArray>(sloppyElements.objects[kSloppyArgumentsArgumentsIndex]) + Cast<FixedArray>(sloppyElements.arguments) otherwise Bailout; const unmappedElementsLength: Smi = unmappedElements.length; if (SmiAbove(end, unmappedElementsLength)) goto Bailout; - const argumentsContext: Context = - UnsafeCast<Context>(sloppyElements.objects[kSloppyArgumentsContextIndex]); + const argumentsContext: Context = sloppyElements.context; const arrayMap: Map = LoadJSArrayElementsMap(ElementsKind::HOLEY_ELEMENTS, context); @@ -63,8 +60,7 @@ macro HandleFastAliasedSloppyArgumentsSlice( // Fill in the part of the result that map to context-mapped parameters. for (let current: Smi = start; current < to; ++current) { - const e: Object = - sloppyElements.objects[current + kSloppyArgumentsParameterMapStart]; + const e: Object = sloppyElements.mapped_entries[current]; const newElement = UnsafeCast<(JSAny | TheHole)>( e != TheHole ? argumentsContext[UnsafeCast<Smi>(e)] : unmappedElements.objects[current]); diff --git a/chromium/v8/src/builtins/base.tq b/chromium/v8/src/builtins/base.tq index 1d2c4546461..b42923412b1 100644 --- a/chromium/v8/src/builtins/base.tq +++ b/chromium/v8/src/builtins/base.tq @@ -78,7 +78,8 @@ type JSPrimitive = Numeric|String|Symbol|Boolean|Null|Undefined; // TheHole or FixedArray. type JSAny = JSReceiver|JSPrimitive; -type JSAnyNotNumber = BigInt|String|Symbol|Boolean|Null|Undefined|JSReceiver; +type JSAnyNotNumeric = String|Symbol|Boolean|Null|Undefined|JSReceiver; +type JSAnyNotNumber = BigInt|JSAnyNotNumeric; // This is the intersection of JSAny and HeapObject. type JSAnyNotSmi = JSAnyNotNumber|HeapNumber; @@ -134,6 +135,7 @@ const kDoubleHole: float64_or_hole = float64_or_hole{is_hole: true, value: 0}; // The HashTable inheritance hierarchy doesn't actually look like this in C++ // because it uses some class templates that we can't yet (and may never) // express in Torque, but this is the expected organization of instance types. +@doNotGenerateCast extern class HashTable extends FixedArray generates 'TNode<FixedArray>'; extern class OrderedHashMap extends HashTable; extern class OrderedHashSet extends HashTable; @@ -264,6 +266,7 @@ extern enum MessageTemplate { kNotGeneric, kCalledNonCallable, kCalledOnNullOrUndefined, + kCannotConvertToPrimitive, kProtoObjectOrNull, kInvalidOffset, kInvalidTypedArrayLength, @@ -307,6 +310,7 @@ extern enum MessageTemplate { kProxyGetPrototypeOfNonExtensible, kProxySetPrototypeOfNonExtensible, kProxyDeletePropertyNonExtensible, + kUndefinedOrNullToObject, kWeakRefsCleanupMustBeCallable, kWasmTrapUnreachable, kWasmTrapMemOutOfBounds, @@ -320,14 +324,24 @@ extern enum MessageTemplate { kWasmTrapDataSegmentDropped, kWasmTrapElemSegmentDropped, kWasmTrapTableOutOfBounds, - kWasmTrapBrOnExnNullRef, - kWasmTrapRethrowNullRef, + kWasmTrapBrOnExnNull, + kWasmTrapRethrowNull, kWasmTrapNullDereference, kWasmTrapIllegalCast, kWasmTrapArrayOutOfBounds, ... } +extern enum PropertyAttributes extends int31 { + NONE, + READ_ONLY, + DONT_ENUM, + DONT_DELETE, + ALL_ATTRIBUTES_MASK, + FROZEN, + ... +} + const kMaxArrayIndex: constexpr uint32 generates 'JSArray::kMaxArrayIndex'; const kArrayBufferMaxByteLength: @@ -364,12 +378,6 @@ const kMaxRegularHeapObjectSize: constexpr int31 const kMaxNewSpaceFixedArrayElements: constexpr int31 generates 'FixedArray::kMaxRegularLength'; -const kSloppyArgumentsArgumentsIndex: constexpr int31 - generates 'SloppyArgumentsElements::kArgumentsIndex'; -const kSloppyArgumentsContextIndex: constexpr int31 - generates 'SloppyArgumentsElements::kContextIndex'; -const kSloppyArgumentsParameterMapStart: constexpr int31 - generates 'SloppyArgumentsElements::kParameterMapStart'; extern enum PrimitiveType { kString, kBoolean, kSymbol, kNumber } @@ -387,7 +395,9 @@ type Boolean = True|False; type NumberOrUndefined = Number|Undefined; +extern macro DefaultStringConstant(): String; extern macro EmptyStringConstant(): EmptyString; +extern macro ErrorsStringConstant(): String; extern macro FalseConstant(): False; extern macro Int32FalseConstant(): bool; extern macro Int32TrueConstant(): bool; @@ -396,11 +406,17 @@ extern macro LengthStringConstant(): String; extern macro MatchSymbolConstant(): Symbol; extern macro MessageStringConstant(): String; extern macro NanConstant(): NaN; +extern macro NameStringConstant(): String; extern macro NullConstant(): Null; +extern macro NumberStringConstant(): String; extern macro ReturnStringConstant(): String; +extern macro StringStringConstant(): String; extern macro TheHoleConstant(): TheHole; +extern macro ToPrimitiveSymbolConstant(): PublicSymbol; +extern macro ToStringStringConstant(): String; extern macro TrueConstant(): True; extern macro UndefinedConstant(): Undefined; +extern macro ValueOfStringConstant(): String; const TheHole: TheHole = TheHoleConstant(); const Null: Null = NullConstant(); @@ -459,7 +475,7 @@ extern macro Print(Object); extern macro DebugBreak(); // ES6 7.1.4 ToInteger ( argument ) -transitioning macro ToIntegerImpl(implicit context: Context)(input: Object): +transitioning macro ToIntegerImpl(implicit context: Context)(input: JSAny): Number { let input = input; @@ -478,28 +494,28 @@ transitioning macro ToIntegerImpl(implicit context: Context)(input: Object): assert(IsNumberNormalized(result)); return result; } - case (ho: HeapObject): { - input = math::NonNumberToNumber(ho); + case (a: JSAnyNotNumber): { + input = conversion::NonNumberToNumber(a); } } } unreachable; } -transitioning builtin ToInteger(implicit context: Context)(input: Object): +transitioning builtin ToInteger(implicit context: Context)(input: JSAny): Number { return ToIntegerImpl(input); } @export -transitioning macro ToInteger_Inline(implicit context: Context)(input: Object): +transitioning macro ToInteger_Inline(implicit context: Context)(input: JSAny): Number { typeswitch (input) { case (s: Smi): { return s; } - case (ho: HeapObject): { - return ToInteger(ho); + case (JSAny): { + return ToInteger(input); } } } @@ -518,6 +534,8 @@ extern transitioning macro GetProperty(implicit context: Context)( JSAny, JSAny): JSAny; extern transitioning builtin SetProperty(implicit context: Context)( JSAny, JSAny, JSAny): JSAny; +extern transitioning builtin SetPropertyIgnoreAttributes( + implicit context: Context)(JSObject, String, JSAny, Smi): JSAny; extern transitioning builtin SetPropertyInLiteral(implicit context: Context)( JSAny, JSAny, JSAny): JSAny; extern transitioning builtin DeleteProperty(implicit context: Context)( @@ -529,6 +547,8 @@ extern transitioning macro HasProperty_Inline(implicit context: Context)( extern builtin LoadIC( Context, JSAny, JSAny, TaggedIndex, FeedbackVector): JSAny; +extern macro SetPropertyStrict(Context, Object, Object, Object): Object; + extern macro ThrowRangeError(implicit context: Context)( constexpr MessageTemplate): never; extern macro ThrowRangeError(implicit context: Context)( @@ -581,10 +601,6 @@ extern builtin ToObject(Context, JSAny): JSReceiver; extern macro ToObject_Inline(Context, JSAny): JSReceiver; extern macro IsNullOrUndefined(Object): bool; extern macro IsString(HeapObject): bool; -transitioning builtin ToString(context: Context, o: JSAny): String { - return ToStringImpl(context, o); -} -extern transitioning runtime ToStringRT(Context, JSAny): String; extern transitioning builtin NonPrimitiveToPrimitive_String( Context, JSAny): JSPrimitive; extern transitioning builtin NonPrimitiveToPrimitive_Default( @@ -616,6 +632,18 @@ extern macro StringCharCodeAt(String, uintptr): int32; extern runtime StringCompareSequence(Context, String, String, Number): Boolean; extern macro StringFromSingleCharCode(int32): String; +extern macro NumberToString(Number): String; +extern macro StringToNumber(String): Number; +extern transitioning macro NonNumberToNumber(implicit context: Context)( + JSAnyNotNumber): Number; +extern transitioning macro NonNumberToNumeric(implicit context: Context)( + JSAnyNotNumber): Numeric; + +extern macro Equal(JSAny, JSAny, Context): Boolean; +macro Equal(implicit context: Context)(left: JSAny, right: JSAny): Boolean { + return Equal(left, right); +} + extern macro StrictEqual(JSAny, JSAny): Boolean; extern macro SmiLexicographicCompare(Smi, Smi): Smi; extern runtime ReThrow(Context, JSAny): never; @@ -778,6 +806,8 @@ extern operator '+' macro ConstexprInt31Add( constexpr int31, constexpr int31): constexpr int31; extern operator '*' macro ConstexprInt31Mul( constexpr int31, constexpr int31): constexpr int31; +extern operator '-' macro Int32Sub(int16, int16): int32; +extern operator '-' macro Int32Sub(uint16, uint16): int32; extern operator '-' macro Int32Sub(int32, int32): int32; extern operator '*' macro Int32Mul(int32, int32): int32; extern operator '/' macro Int32Div(int32, int32): int32; @@ -814,6 +844,7 @@ extern operator '+' macro Float64Add(float64, float64): float64; extern operator '-' macro Float64Sub(float64, float64): float64; extern operator '*' macro Float64Mul(float64, float64): float64; extern operator '/' macro Float64Div(float64, float64): float64; +extern operator '%' macro Float64Mod(float64, float64): float64; extern operator '+' macro NumberAdd(Number, Number): Number; extern operator '-' macro NumberSub(Number, Number): Number; @@ -850,6 +881,12 @@ extern operator '!' macro ConstexprBoolNot(constexpr bool): constexpr bool; extern operator '!' macro Word32BinaryNot(bool): bool; extern operator '!' macro IsFalse(Boolean): bool; +extern operator '==' macro +ConstexprInt31Equal( + constexpr InstanceType, constexpr InstanceType): constexpr bool; +extern operator '-' macro ConstexprUint32Sub( + constexpr InstanceType, constexpr InstanceType): constexpr int32; + extern operator '.instanceType' macro LoadInstanceType(HeapObject): InstanceType; @@ -882,6 +919,7 @@ extern macro TaggedIsNotSmi(Object): bool; extern macro TaggedIsPositiveSmi(Object): bool; extern macro IsValidPositiveSmi(intptr): bool; +extern macro IsInteger(JSAny): bool; extern macro IsInteger(HeapNumber): bool; extern macro AllocateHeapNumberWithValue(float64): HeapNumber; @@ -912,6 +950,7 @@ macro SmiTag<T : type extends uint31>(value: T): SmiTagged<T> { return %RawDownCast<SmiTagged<T>>(SmiFromUint32(value)); } extern macro SmiToInt32(Smi): int32; +extern macro SmiToFloat64(Smi): float64; extern macro TaggedIndexToIntPtr(TaggedIndex): intptr; extern macro IntPtrToTaggedIndex(intptr): TaggedIndex; extern macro TaggedIndexToSmi(TaggedIndex): Smi; @@ -919,6 +958,7 @@ extern macro SmiToTaggedIndex(Smi): TaggedIndex; extern macro RoundIntPtrToFloat64(intptr): float64; extern macro ChangeFloat32ToFloat64(float32): float64; extern macro ChangeNumberToFloat64(Number): float64; +extern macro ChangeNumberToUint32(Number): uint32; extern macro ChangeTaggedNonSmiToInt32(implicit context: Context)(JSAnyNotSmi): int32; extern macro ChangeTaggedToFloat64(implicit context: Context)(JSAny): float64; @@ -938,6 +978,7 @@ extern macro NumberConstant(constexpr int32): Number; extern macro NumberConstant(constexpr uint32): Number; extern macro IntPtrConstant(constexpr int31): intptr; extern macro IntPtrConstant(constexpr int32): intptr; +extern macro Uint16Constant(constexpr uint16): uint16; extern macro Int32Constant(constexpr int31): int31; extern macro Int32Constant(constexpr int32): int32; extern macro Float64Constant(constexpr int31): float64; @@ -962,22 +1003,6 @@ extern macro BitcastWordToTagged(uintptr): Object; extern macro BitcastTaggedToWord(Tagged): intptr; extern macro BitcastTaggedToWordForTagAndSmiBits(Tagged): intptr; -macro Is<A : type extends Object, B : type extends Object>( - implicit context: Context)(o: B): bool { - Cast<A>(o) otherwise return false; - return true; -} - -macro UnsafeCast<A : type extends Object>(implicit context: Context)(o: Object): - A { - assert(Is<A>(o)); - return %RawDownCast<A>(o); -} - -macro UnsafeConstCast<T: type>(r: const &T):&T { - return %RawDownCast<&T>(r); -} - extern macro FixedArrayMapConstant(): Map; extern macro FixedDoubleArrayMapConstant(): Map; extern macro FixedCOWArrayMapConstant(): Map; @@ -986,7 +1011,6 @@ extern macro EmptyFixedArrayConstant(): EmptyFixedArray; extern macro PromiseCapabilityMapConstant(): Map; extern macro OneByteStringMapConstant(): Map; extern macro StringMapConstant(): Map; -extern macro SloppyArgumentsElementsMapConstant(): Map; const kFixedArrayMap: Map = FixedArrayMapConstant(); const kFixedDoubleArrayMap: Map = FixedDoubleArrayMapConstant(); @@ -998,7 +1022,6 @@ const kPromiseCapabilityMap: Map = PromiseCapabilityMapConstant(); const kOneByteStringMap: Map = OneByteStringMapConstant(); // The map of a non-internalized internal SeqTwoByteString. const kStringMap: Map = StringMapConstant(); -const kSloppyArgumentsElementsMap: Map = SloppyArgumentsElementsMapConstant(); extern macro IsPrototypeInitialArrayPrototype(implicit context: Context)(Map): bool; @@ -1371,7 +1394,6 @@ transitioning macro GetMethod(implicit context: Context)( MessageTemplate::kPropertyNotFunction, value, symbol, o); } -extern macro NumberToString(Number): String; extern macro IsOneByteStringInstanceType(InstanceType): bool; // After converting an index to an integer, calculate a relative index: @@ -1514,6 +1536,9 @@ macro IsFastJSArrayForReadWithNoCustomIteration(context: Context, o: Object): extern transitioning runtime CreateDataProperty(implicit context: Context)(JSReceiver, JSAny, JSAny); +extern transitioning runtime SetOwnPropertyIgnoreAttributes( + implicit context: Context)(JSObject, String, JSAny, Smi); + namespace runtime { extern runtime GetDerivedMap(Context, JSFunction, JSReceiver): Map; @@ -1573,35 +1598,6 @@ transitioning builtin FastCreateDataProperty(implicit context: Context)( return Undefined; } -@export -transitioning macro ToStringImpl(context: Context, o: JSAny): String { - let result: JSAny = o; - while (true) { - typeswitch (result) { - case (num: Number): { - return NumberToString(num); - } - case (str: String): { - return str; - } - case (oddball: Oddball): { - return oddball.to_string; - } - case (JSReceiver): { - result = NonPrimitiveToPrimitive_String(context, result); - continue; - } - case (Symbol): { - ThrowTypeError(MessageTemplate::kSymbolToString); - } - case (JSAny): { - return ToStringRT(context, o); - } - } - } - unreachable; -} - macro VerifiedUnreachable(): never { StaticAssert(false); unreachable; diff --git a/chromium/v8/src/builtins/bigint.tq b/chromium/v8/src/builtins/bigint.tq index d52de7f84ea..409301dcc98 100644 --- a/chromium/v8/src/builtins/bigint.tq +++ b/chromium/v8/src/builtins/bigint.tq @@ -13,6 +13,7 @@ type BigInt extends BigIntBase; @noVerifier @hasSameInstanceTypeAsParent +@doNotGenerateCast extern class MutableBigInt extends BigIntBase generates 'TNode<BigInt>' { } diff --git a/chromium/v8/src/builtins/builtins-array-gen.cc b/chromium/v8/src/builtins/builtins-array-gen.cc index 734b9b634a0..dfd52255830 100644 --- a/chromium/v8/src/builtins/builtins-array-gen.cc +++ b/chromium/v8/src/builtins/builtins-array-gen.cc @@ -438,7 +438,6 @@ TF_BUILTIN(ArrayPrototypePush, CodeStubAssembler) { } TF_BUILTIN(ExtractFastJSArray, ArrayBuiltinsAssembler) { - ParameterMode mode = OptimalParameterMode(); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); TNode<JSArray> array = CAST(Parameter(Descriptor::kSource)); TNode<BInt> begin = SmiToBInt(CAST(Parameter(Descriptor::kBegin))); @@ -446,7 +445,7 @@ TF_BUILTIN(ExtractFastJSArray, ArrayBuiltinsAssembler) { CSA_ASSERT(this, Word32BinaryNot(IsNoElementsProtectorCellInvalid())); - Return(ExtractFastJSArray(context, array, begin, count, mode)); + Return(ExtractFastJSArray(context, array, begin, count)); } TF_BUILTIN(CloneFastJSArray, ArrayBuiltinsAssembler) { @@ -477,7 +476,7 @@ TF_BUILTIN(CloneFastJSArrayFillingHoles, ArrayBuiltinsAssembler) { LoadElementsKind(array))), Word32BinaryNot(IsNoElementsProtectorCellInvalid()))); - Return(CloneFastJSArray(context, array, {}, + Return(CloneFastJSArray(context, array, base::nullopt, HoleConversionMode::kConvertToUndefined)); } @@ -1153,7 +1152,7 @@ TF_BUILTIN(ArrayIndexOfHoleyDoubles, ArrayIncludesIndexofAssembler) { // ES #sec-array.prototype.values TF_BUILTIN(ArrayPrototypeValues, CodeStubAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<NativeContext> context = CAST(Parameter(Descriptor::kContext)); TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver)); Return(CreateArrayIterator(context, ToObject_Inline(context, receiver), IterationKind::kValues)); @@ -1161,7 +1160,7 @@ TF_BUILTIN(ArrayPrototypeValues, CodeStubAssembler) { // ES #sec-array.prototype.entries TF_BUILTIN(ArrayPrototypeEntries, CodeStubAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<NativeContext> context = CAST(Parameter(Descriptor::kContext)); TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver)); Return(CreateArrayIterator(context, ToObject_Inline(context, receiver), IterationKind::kEntries)); @@ -1169,7 +1168,7 @@ TF_BUILTIN(ArrayPrototypeEntries, CodeStubAssembler) { // ES #sec-array.prototype.keys TF_BUILTIN(ArrayPrototypeKeys, CodeStubAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<NativeContext> context = CAST(Parameter(Descriptor::kContext)); TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver)); Return(CreateArrayIterator(context, ToObject_Inline(context, receiver), IterationKind::kKeys)); @@ -1665,7 +1664,8 @@ void ArrayBuiltinsAssembler::TailCallArrayConstructorStub( void ArrayBuiltinsAssembler::CreateArrayDispatchNoArgument( TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc, - AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) { + AllocationSiteOverrideMode mode, + base::Optional<TNode<AllocationSite>> allocation_site) { if (mode == DISABLE_ALLOCATION_SITES) { Callable callable = CodeFactory::ArrayNoArgumentConstructor( isolate(), GetInitialFastElementsKind(), mode); @@ -1674,7 +1674,8 @@ void ArrayBuiltinsAssembler::CreateArrayDispatchNoArgument( argc); } else { DCHECK_EQ(mode, DONT_OVERRIDE); - TNode<Int32T> elements_kind = LoadElementsKind(allocation_site); + DCHECK(allocation_site); + TNode<Int32T> elements_kind = LoadElementsKind(*allocation_site); // TODO(ishell): Compute the builtin index dynamically instead of // iterating over all expected elements kinds. @@ -1688,7 +1689,7 @@ void ArrayBuiltinsAssembler::CreateArrayDispatchNoArgument( Callable callable = CodeFactory::ArrayNoArgumentConstructor(isolate(), kind, mode); - TailCallArrayConstructorStub(callable, context, target, allocation_site, + TailCallArrayConstructorStub(callable, context, target, *allocation_site, argc); BIND(&next); @@ -1701,7 +1702,8 @@ void ArrayBuiltinsAssembler::CreateArrayDispatchNoArgument( void ArrayBuiltinsAssembler::CreateArrayDispatchSingleArgument( TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc, - AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) { + AllocationSiteOverrideMode mode, + base::Optional<TNode<AllocationSite>> allocation_site) { if (mode == DISABLE_ALLOCATION_SITES) { ElementsKind initial = GetInitialFastElementsKind(); ElementsKind holey_initial = GetHoleyElementsKind(initial); @@ -1712,7 +1714,8 @@ void ArrayBuiltinsAssembler::CreateArrayDispatchSingleArgument( argc); } else { DCHECK_EQ(mode, DONT_OVERRIDE); - TNode<Smi> transition_info = LoadTransitionInfo(allocation_site); + DCHECK(allocation_site); + TNode<Smi> transition_info = LoadTransitionInfo(*allocation_site); // Least significant bit in fast array elements kind means holeyness. STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0); @@ -1735,7 +1738,7 @@ void ArrayBuiltinsAssembler::CreateArrayDispatchSingleArgument( // Make elements kind holey and update elements kind in the type info. var_elements_kind = Word32Or(var_elements_kind.value(), Int32Constant(1)); StoreObjectFieldNoWriteBarrier( - allocation_site, AllocationSite::kTransitionInfoOrBoilerplateOffset, + *allocation_site, AllocationSite::kTransitionInfoOrBoilerplateOffset, SmiOr(transition_info, SmiConstant(fast_elements_kind_holey_mask))); Goto(&normal_sequence); } @@ -1756,7 +1759,7 @@ void ArrayBuiltinsAssembler::CreateArrayDispatchSingleArgument( Callable callable = CodeFactory::ArraySingleArgumentConstructor(isolate(), kind, mode); - TailCallArrayConstructorStub(callable, context, target, allocation_site, + TailCallArrayConstructorStub(callable, context, target, *allocation_site, argc); BIND(&next); @@ -1769,7 +1772,8 @@ void ArrayBuiltinsAssembler::CreateArrayDispatchSingleArgument( void ArrayBuiltinsAssembler::GenerateDispatchToArrayStub( TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc, - AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) { + AllocationSiteOverrideMode mode, + base::Optional<TNode<AllocationSite>> allocation_site) { Label check_one_case(this), fallthrough(this); GotoIfNot(Word32Equal(argc, Int32Constant(0)), &check_one_case); CreateArrayDispatchNoArgument(context, target, argc, mode, allocation_site); @@ -1862,8 +1866,9 @@ void ArrayBuiltinsAssembler::GenerateConstructor( { TNode<JSArray> array = AllocateJSArray( elements_kind, array_map, array_size_smi, array_size_smi, - mode == DONT_TRACK_ALLOCATION_SITE ? TNode<AllocationSite>() - : CAST(allocation_site)); + mode == DONT_TRACK_ALLOCATION_SITE + ? base::Optional<TNode<AllocationSite>>(base::nullopt) + : CAST(allocation_site)); Return(array); } } @@ -1882,9 +1887,10 @@ void ArrayBuiltinsAssembler::GenerateArrayNoArgumentConstructor( Parameter(Descriptor::kFunction), JSFunction::kContextOffset)); bool track_allocation_site = AllocationSite::ShouldTrack(kind) && mode != DISABLE_ALLOCATION_SITES; - TNode<AllocationSite> allocation_site = - track_allocation_site ? CAST(Parameter(Descriptor::kAllocationSite)) - : TNode<AllocationSite>(); + base::Optional<TNode<AllocationSite>> allocation_site = + track_allocation_site + ? CAST(Parameter(Descriptor::kAllocationSite)) + : base::Optional<TNode<AllocationSite>>(base::nullopt); TNode<Map> array_map = LoadJSArrayElementsMap(kind, native_context); TNode<JSArray> array = AllocateJSArray( kind, array_map, IntPtrConstant(JSArray::kPreallocatedArrayElements), diff --git a/chromium/v8/src/builtins/builtins-array-gen.h b/chromium/v8/src/builtins/builtins-array-gen.h index 088af90665d..96833d9dea2 100644 --- a/chromium/v8/src/builtins/builtins-array-gen.h +++ b/chromium/v8/src/builtins/builtins-array-gen.h @@ -72,20 +72,20 @@ class ArrayBuiltinsAssembler : public CodeStubAssembler { TNode<JSFunction> target, TNode<HeapObject> allocation_site_or_undefined, TNode<Int32T> argc); - void GenerateDispatchToArrayStub(TNode<Context> context, - TNode<JSFunction> target, TNode<Int32T> argc, - AllocationSiteOverrideMode mode, - TNode<AllocationSite> allocation_site = {}); + void GenerateDispatchToArrayStub( + TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc, + AllocationSiteOverrideMode mode, + base::Optional<TNode<AllocationSite>> allocation_site = base::nullopt); void CreateArrayDispatchNoArgument( TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc, AllocationSiteOverrideMode mode, - TNode<AllocationSite> allocation_site = {}); + base::Optional<TNode<AllocationSite>> allocation_site); void CreateArrayDispatchSingleArgument( TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc, AllocationSiteOverrideMode mode, - TNode<AllocationSite> allocation_site = {}); + base::Optional<TNode<AllocationSite>> allocation_site); void GenerateConstructor(TNode<Context> context, TNode<HeapObject> array_function, diff --git a/chromium/v8/src/builtins/builtins-async-iterator-gen.cc b/chromium/v8/src/builtins/builtins-async-iterator-gen.cc index b138515af65..73e5605ccc4 100644 --- a/chromium/v8/src/builtins/builtins-async-iterator-gen.cc +++ b/chromium/v8/src/builtins/builtins-async-iterator-gen.cc @@ -16,6 +16,10 @@ namespace internal { namespace { class AsyncFromSyncBuiltinsAssembler : public AsyncBuiltinsAssembler { public: + // The 'next' and 'return' take an optional value parameter, and the 'throw' + // method take an optional reason parameter. + static const int kValueOrReasonArg = 0; + explicit AsyncFromSyncBuiltinsAssembler(compiler::CodeAssemblerState* state) : AsyncBuiltinsAssembler(state) {} @@ -31,8 +35,8 @@ class AsyncFromSyncBuiltinsAssembler : public AsyncBuiltinsAssembler { using SyncIteratorNodeGenerator = std::function<TNode<Object>(TNode<JSReceiver>)>; void Generate_AsyncFromSyncIteratorMethod( - const TNode<Context> context, const TNode<Object> iterator, - const TNode<Object> sent_value, + CodeStubArguments* args, const TNode<Context> context, + const TNode<Object> iterator, const TNode<Object> sent_value, const SyncIteratorNodeGenerator& get_method, const UndefinedMethodHandler& if_method_undefined, const char* operation_name, @@ -40,9 +44,9 @@ class AsyncFromSyncBuiltinsAssembler : public AsyncBuiltinsAssembler { base::Optional<TNode<Object>> initial_exception_value = base::nullopt); void Generate_AsyncFromSyncIteratorMethod( - const TNode<Context> context, const TNode<Object> iterator, - const TNode<Object> sent_value, Handle<String> name, - const UndefinedMethodHandler& if_method_undefined, + CodeStubArguments* args, const TNode<Context> context, + const TNode<Object> iterator, const TNode<Object> sent_value, + Handle<String> name, const UndefinedMethodHandler& if_method_undefined, const char* operation_name, Label::Type reject_label_type = Label::kDeferred, base::Optional<TNode<Object>> initial_exception_value = base::nullopt) { @@ -50,7 +54,7 @@ class AsyncFromSyncBuiltinsAssembler : public AsyncBuiltinsAssembler { return GetProperty(context, sync_iterator, name); }; return Generate_AsyncFromSyncIteratorMethod( - context, iterator, sent_value, get_method, if_method_undefined, + args, context, iterator, sent_value, get_method, if_method_undefined, operation_name, reject_label_type, initial_exception_value); } @@ -97,8 +101,9 @@ void AsyncFromSyncBuiltinsAssembler::ThrowIfNotAsyncFromSyncIterator( } void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod( - const TNode<Context> context, const TNode<Object> iterator, - const TNode<Object> sent_value, const SyncIteratorNodeGenerator& get_method, + CodeStubArguments* args, const TNode<Context> context, + const TNode<Object> iterator, const TNode<Object> sent_value, + const SyncIteratorNodeGenerator& get_method, const UndefinedMethodHandler& if_method_undefined, const char* operation_name, Label::Type reject_label_type, base::Optional<TNode<Object>> initial_exception_value) { @@ -122,22 +127,37 @@ void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod( if (if_method_undefined) { Label if_isnotundefined(this); - GotoIfNot(IsUndefined(method), &if_isnotundefined); + GotoIfNot(IsNullOrUndefined(method), &if_isnotundefined); if_method_undefined(native_context, promise, &reject_promise); BIND(&if_isnotundefined); } - TNode<Object> iter_result; + TVARIABLE(Object, iter_result); { + Label has_sent_value(this), no_sent_value(this), merge(this); ScopedExceptionHandler handler(this, &reject_promise, &var_exception); - iter_result = Call(context, method, sync_iterator, sent_value); + Branch( + IntPtrGreaterThan(args->GetLength(), IntPtrConstant(kValueOrReasonArg)), + &has_sent_value, &no_sent_value); + BIND(&has_sent_value); + { + iter_result = Call(context, method, sync_iterator, sent_value); + Goto(&merge); + } + BIND(&no_sent_value); + { + iter_result = Call(context, method, sync_iterator); + Goto(&merge); + } + BIND(&merge); } TNode<Object> value; TNode<Oddball> done; - std::tie(value, done) = LoadIteratorResult( - context, native_context, iter_result, &reject_promise, &var_exception); + std::tie(value, done) = + LoadIteratorResult(context, native_context, iter_result.value(), + &reject_promise, &var_exception); const TNode<JSFunction> promise_fun = CAST(LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX)); @@ -160,15 +180,16 @@ void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod( // Perform ! PerformPromiseThen(valueWrapper, // onFulfilled, undefined, promiseCapability). - Return(CallBuiltin(Builtins::kPerformPromiseThen, context, value_wrapper, - on_fulfilled, UndefinedConstant(), promise)); + args->PopAndReturn(CallBuiltin(Builtins::kPerformPromiseThen, context, + value_wrapper, on_fulfilled, + UndefinedConstant(), promise)); BIND(&reject_promise); { const TNode<Object> exception = var_exception.value(); CallBuiltin(Builtins::kRejectPromise, context, promise, exception, TrueConstant()); - Return(promise); + args->PopAndReturn(promise); } } @@ -252,8 +273,12 @@ AsyncFromSyncBuiltinsAssembler::LoadIteratorResult( // https://tc39.github.io/proposal-async-iteration/ // Section #sec-%asyncfromsynciteratorprototype%.next TF_BUILTIN(AsyncFromSyncIteratorPrototypeNext, AsyncFromSyncBuiltinsAssembler) { - const TNode<Object> iterator = CAST(Parameter(Descriptor::kReceiver)); - const TNode<Object> value = CAST(Parameter(Descriptor::kValue)); + TNode<IntPtrT> argc = ChangeInt32ToIntPtr( + UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount))); + CodeStubArguments args(this, argc); + + const TNode<Object> iterator = args.GetReceiver(); + const TNode<Object> value = args.GetOptionalArgumentValue(kValueOrReasonArg); const TNode<Context> context = CAST(Parameter(Descriptor::kContext)); auto get_method = [=](const TNode<JSReceiver> unused) { @@ -261,7 +286,7 @@ TF_BUILTIN(AsyncFromSyncIteratorPrototypeNext, AsyncFromSyncBuiltinsAssembler) { JSAsyncFromSyncIterator::kNextOffset); }; Generate_AsyncFromSyncIteratorMethod( - context, iterator, value, get_method, UndefinedMethodHandler(), + &args, context, iterator, value, get_method, UndefinedMethodHandler(), "[Async-from-Sync Iterator].prototype.next"); } @@ -269,11 +294,16 @@ TF_BUILTIN(AsyncFromSyncIteratorPrototypeNext, AsyncFromSyncBuiltinsAssembler) { // Section #sec-%asyncfromsynciteratorprototype%.return TF_BUILTIN(AsyncFromSyncIteratorPrototypeReturn, AsyncFromSyncBuiltinsAssembler) { - const TNode<Object> iterator = CAST(Parameter(Descriptor::kReceiver)); - const TNode<Object> value = CAST(Parameter(Descriptor::kValue)); + TNode<IntPtrT> argc = ChangeInt32ToIntPtr( + UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount))); + CodeStubArguments args(this, argc); + + const TNode<Object> iterator = args.GetReceiver(); + const TNode<Object> value = args.GetOptionalArgumentValue(kValueOrReasonArg); const TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - auto if_return_undefined = [=](const TNode<NativeContext> native_context, + auto if_return_undefined = [=, &args]( + const TNode<NativeContext> native_context, const TNode<JSPromise> promise, Label* if_exception) { // If return is undefined, then @@ -285,20 +315,24 @@ TF_BUILTIN(AsyncFromSyncIteratorPrototypeReturn, // IfAbruptRejectPromise(nextDone, promiseCapability). // Return promiseCapability.[[Promise]]. CallBuiltin(Builtins::kResolvePromise, context, promise, iter_result); - Return(promise); + args.PopAndReturn(promise); }; Generate_AsyncFromSyncIteratorMethod( - context, iterator, value, factory()->return_string(), if_return_undefined, - "[Async-from-Sync Iterator].prototype.return"); + &args, context, iterator, value, factory()->return_string(), + if_return_undefined, "[Async-from-Sync Iterator].prototype.return"); } // https://tc39.github.io/proposal-async-iteration/ // Section #sec-%asyncfromsynciteratorprototype%.throw TF_BUILTIN(AsyncFromSyncIteratorPrototypeThrow, AsyncFromSyncBuiltinsAssembler) { - const TNode<Object> iterator = CAST(Parameter(Descriptor::kReceiver)); - const TNode<Object> reason = CAST(Parameter(Descriptor::kReason)); + TNode<IntPtrT> argc = ChangeInt32ToIntPtr( + UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount))); + CodeStubArguments args(this, argc); + + const TNode<Object> iterator = args.GetReceiver(); + const TNode<Object> reason = args.GetOptionalArgumentValue(kValueOrReasonArg); const TNode<Context> context = CAST(Parameter(Descriptor::kContext)); auto if_throw_undefined = [=](const TNode<NativeContext> native_context, @@ -306,9 +340,9 @@ TF_BUILTIN(AsyncFromSyncIteratorPrototypeThrow, Label* if_exception) { Goto(if_exception); }; Generate_AsyncFromSyncIteratorMethod( - context, iterator, reason, factory()->throw_string(), if_throw_undefined, - "[Async-from-Sync Iterator].prototype.throw", Label::kNonDeferred, - reason); + &args, context, iterator, reason, factory()->throw_string(), + if_throw_undefined, "[Async-from-Sync Iterator].prototype.throw", + Label::kNonDeferred, reason); } } // namespace internal diff --git a/chromium/v8/src/builtins/builtins-call-gen.cc b/chromium/v8/src/builtins/builtins-call-gen.cc index d457e033149..f7919b78f47 100644 --- a/chromium/v8/src/builtins/builtins-call-gen.cc +++ b/chromium/v8/src/builtins/builtins-call-gen.cc @@ -64,6 +64,49 @@ void Builtins::Generate_CallFunctionForwardVarargs(MacroAssembler* masm) { masm->isolate()->builtins()->CallFunction()); } +TF_BUILTIN(Call_ReceiverIsNullOrUndefined_WithFeedback, + CallOrConstructBuiltinsAssembler) { + TNode<Object> target = CAST(Parameter(Descriptor::kFunction)); + TNode<Int32T> argc = + UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount)); + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<HeapObject> maybe_feedback_vector = + CAST(Parameter(Descriptor::kMaybeFeedbackVector)); + TNode<Int32T> slot = UncheckedCast<Int32T>(Parameter(Descriptor::kSlot)); + CollectCallFeedback(target, context, maybe_feedback_vector, + Unsigned(ChangeInt32ToIntPtr(slot))); + TailCallBuiltin(Builtins::kCall_ReceiverIsNullOrUndefined, context, target, + argc); +} + +TF_BUILTIN(Call_ReceiverIsNotNullOrUndefined_WithFeedback, + CallOrConstructBuiltinsAssembler) { + TNode<Object> target = CAST(Parameter(Descriptor::kFunction)); + TNode<Int32T> argc = + UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount)); + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<HeapObject> maybe_feedback_vector = + CAST(Parameter(Descriptor::kMaybeFeedbackVector)); + TNode<Int32T> slot = UncheckedCast<Int32T>(Parameter(Descriptor::kSlot)); + CollectCallFeedback(target, context, maybe_feedback_vector, + Unsigned(ChangeInt32ToIntPtr(slot))); + TailCallBuiltin(Builtins::kCall_ReceiverIsNotNullOrUndefined, context, target, + argc); +} + +TF_BUILTIN(Call_ReceiverIsAny_WithFeedback, CallOrConstructBuiltinsAssembler) { + TNode<Object> target = CAST(Parameter(Descriptor::kFunction)); + TNode<Int32T> argc = + UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount)); + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<HeapObject> maybe_feedback_vector = + CAST(Parameter(Descriptor::kMaybeFeedbackVector)); + TNode<Int32T> slot = UncheckedCast<Int32T>(Parameter(Descriptor::kSlot)); + CollectCallFeedback(target, context, maybe_feedback_vector, + Unsigned(ChangeInt32ToIntPtr(slot))); + TailCallBuiltin(Builtins::kCall_ReceiverIsAny, context, target, argc); +} + void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike( TNode<Object> target, base::Optional<TNode<Object>> new_target, TNode<Object> arguments_list, TNode<Context> context) { @@ -387,6 +430,19 @@ TF_BUILTIN(CallWithArrayLike, CallOrConstructBuiltinsAssembler) { CallOrConstructWithArrayLike(target, new_target, arguments_list, context); } +TF_BUILTIN(CallWithArrayLike_WithFeedback, CallOrConstructBuiltinsAssembler) { + TNode<Object> target = CAST(Parameter(Descriptor::kTarget)); + base::Optional<TNode<Object>> new_target = base::nullopt; + TNode<Object> arguments_list = CAST(Parameter(Descriptor::kArgumentsList)); + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<HeapObject> maybe_feedback_vector = + CAST(Parameter(Descriptor::kMaybeFeedbackVector)); + TNode<Int32T> slot = UncheckedCast<Int32T>(Parameter(Descriptor::kSlot)); + CollectCallFeedback(target, context, maybe_feedback_vector, + Unsigned(ChangeInt32ToIntPtr(slot))); + CallOrConstructWithArrayLike(target, new_target, arguments_list, context); +} + TF_BUILTIN(CallWithSpread, CallOrConstructBuiltinsAssembler) { TNode<Object> target = CAST(Parameter(Descriptor::kTarget)); base::Optional<TNode<Object>> new_target = base::nullopt; @@ -397,6 +453,21 @@ TF_BUILTIN(CallWithSpread, CallOrConstructBuiltinsAssembler) { CallOrConstructWithSpread(target, new_target, spread, args_count, context); } +TF_BUILTIN(CallWithSpread_WithFeedback, CallOrConstructBuiltinsAssembler) { + TNode<Object> target = CAST(Parameter(Descriptor::kTarget)); + base::Optional<TNode<Object>> new_target = base::nullopt; + TNode<Object> spread = CAST(Parameter(Descriptor::kSpread)); + TNode<Int32T> args_count = + UncheckedCast<Int32T>(Parameter(Descriptor::kArgumentsCount)); + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<HeapObject> maybe_feedback_vector = + CAST(Parameter(Descriptor::kMaybeFeedbackVector)); + TNode<Int32T> slot = UncheckedCast<Int32T>(Parameter(Descriptor::kSlot)); + CollectCallFeedback(target, context, maybe_feedback_vector, + Unsigned(ChangeInt32ToIntPtr(slot))); + CallOrConstructWithSpread(target, new_target, spread, args_count, context); +} + TNode<JSReceiver> CallOrConstructBuiltinsAssembler::GetCompatibleReceiver( TNode<JSReceiver> receiver, TNode<HeapObject> signature, TNode<Context> context) { @@ -535,7 +606,7 @@ void CallOrConstructBuiltinsAssembler::CallFunctionTemplate( TNode<IntPtrT> function_template_info_flags = LoadAndUntagObjectField( function_template_info, FunctionTemplateInfo::kFlagOffset); Branch(IsSetWord(function_template_info_flags, - 1 << FunctionTemplateInfo::kAcceptAnyReceiver), + 1 << FunctionTemplateInfo::AcceptAnyReceiverBit::kShift), &receiver_done, &receiver_needs_access_check); BIND(&receiver_needs_access_check); diff --git a/chromium/v8/src/builtins/builtins-collections-gen.cc b/chromium/v8/src/builtins/builtins-collections-gen.cc index 2f0e5a75602..3ab4392b87c 100644 --- a/chromium/v8/src/builtins/builtins-collections-gen.cc +++ b/chromium/v8/src/builtins/builtins-collections-gen.cc @@ -761,7 +761,7 @@ void CollectionsBuiltinsAssembler::FindOrderedHashTableEntry( const TNode<IntPtrT> number_of_buckets = SmiUntag(CAST(UnsafeLoadFixedArrayElement( table, CollectionType::NumberOfBucketsIndex()))); - const TNode<WordT> bucket = + const TNode<IntPtrT> bucket = WordAnd(hash, IntPtrSub(number_of_buckets, IntPtrConstant(1))); const TNode<IntPtrT> first_entry = SmiUntag(CAST(UnsafeLoadFixedArrayElement( table, bucket, CollectionType::HashTableStartIndex() * kTaggedSize))); diff --git a/chromium/v8/src/builtins/builtins-constructor-gen.cc b/chromium/v8/src/builtins/builtins-constructor-gen.cc index c706ce9306c..4079bc75d14 100644 --- a/chromium/v8/src/builtins/builtins-constructor-gen.cc +++ b/chromium/v8/src/builtins/builtins-constructor-gen.cc @@ -36,6 +36,31 @@ void Builtins::Generate_ConstructFunctionForwardVarargs(MacroAssembler* masm) { BUILTIN_CODE(masm->isolate(), ConstructFunction)); } +TF_BUILTIN(Construct_WithFeedback, CallOrConstructBuiltinsAssembler) { + TNode<Object> target = CAST(Parameter(Descriptor::kTarget)); + TNode<Object> new_target = CAST(Parameter(Descriptor::kNewTarget)); + TNode<Int32T> argc = + UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount)); + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<HeapObject> maybe_feedback_vector = + CAST(Parameter(Descriptor::kMaybeFeedbackVector)); + TNode<Int32T> slot = UncheckedCast<Int32T>(Parameter(Descriptor::kSlot)); + + TVARIABLE(AllocationSite, allocation_site); + Label if_construct_generic(this), if_construct_array(this); + CollectConstructFeedback(context, target, new_target, maybe_feedback_vector, + Unsigned(ChangeInt32ToIntPtr(slot)), + &if_construct_generic, &if_construct_array, + &allocation_site); + + BIND(&if_construct_generic); + TailCallBuiltin(Builtins::kConstruct, context, target, new_target, argc); + + BIND(&if_construct_array); + TailCallBuiltin(Builtins::kArrayConstructorImpl, context, target, new_target, + argc, allocation_site.value()); +} + TF_BUILTIN(ConstructWithArrayLike, CallOrConstructBuiltinsAssembler) { TNode<Object> target = CAST(Parameter(Descriptor::kTarget)); TNode<Object> new_target = CAST(Parameter(Descriptor::kNewTarget)); @@ -44,6 +69,30 @@ TF_BUILTIN(ConstructWithArrayLike, CallOrConstructBuiltinsAssembler) { CallOrConstructWithArrayLike(target, new_target, arguments_list, context); } +TF_BUILTIN(ConstructWithArrayLike_WithFeedback, + CallOrConstructBuiltinsAssembler) { + TNode<Object> target = CAST(Parameter(Descriptor::kTarget)); + TNode<Object> new_target = CAST(Parameter(Descriptor::kNewTarget)); + TNode<Object> arguments_list = CAST(Parameter(Descriptor::kArgumentsList)); + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<HeapObject> maybe_feedback_vector = + CAST(Parameter(Descriptor::kMaybeFeedbackVector)); + TNode<Int32T> slot = UncheckedCast<Int32T>(Parameter(Descriptor::kSlot)); + + TVARIABLE(AllocationSite, allocation_site); + Label if_construct_generic(this), if_construct_array(this); + CollectConstructFeedback(context, target, new_target, maybe_feedback_vector, + Unsigned(ChangeInt32ToIntPtr(slot)), + &if_construct_generic, &if_construct_array, + &allocation_site); + + BIND(&if_construct_array); + Goto(&if_construct_generic); // Not implemented. + + BIND(&if_construct_generic); + CallOrConstructWithArrayLike(target, new_target, arguments_list, context); +} + TF_BUILTIN(ConstructWithSpread, CallOrConstructBuiltinsAssembler) { TNode<Object> target = CAST(Parameter(Descriptor::kTarget)); TNode<Object> new_target = CAST(Parameter(Descriptor::kNewTarget)); @@ -54,6 +103,31 @@ TF_BUILTIN(ConstructWithSpread, CallOrConstructBuiltinsAssembler) { CallOrConstructWithSpread(target, new_target, spread, args_count, context); } +TF_BUILTIN(ConstructWithSpread_WithFeedback, CallOrConstructBuiltinsAssembler) { + TNode<Object> target = CAST(Parameter(Descriptor::kTarget)); + TNode<Object> new_target = CAST(Parameter(Descriptor::kNewTarget)); + TNode<Object> spread = CAST(Parameter(Descriptor::kSpread)); + TNode<Int32T> args_count = + UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount)); + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<HeapObject> maybe_feedback_vector = + CAST(Parameter(Descriptor::kMaybeFeedbackVector)); + TNode<Int32T> slot = UncheckedCast<Int32T>(Parameter(Descriptor::kSlot)); + + TVARIABLE(AllocationSite, allocation_site); + Label if_construct_generic(this), if_construct_array(this); + CollectConstructFeedback(context, target, new_target, maybe_feedback_vector, + Unsigned(ChangeInt32ToIntPtr(slot)), + &if_construct_generic, &if_construct_array, + &allocation_site); + + BIND(&if_construct_array); + Goto(&if_construct_generic); // Not implemented. + + BIND(&if_construct_generic); + CallOrConstructWithSpread(target, new_target, spread, args_count, context); +} + using Node = compiler::Node; TF_BUILTIN(FastNewClosure, ConstructorBuiltinsAssembler) { @@ -691,6 +765,11 @@ TF_BUILTIN(ObjectConstructor, ConstructorBuiltinsAssembler) { args.PopAndReturn(var_result.value()); } +TF_BUILTIN(CreateEmptyLiteralObject, ConstructorBuiltinsAssembler) { + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + Return(EmitCreateEmptyObjectLiteral(context)); +} + // ES #sec-number-constructor TF_BUILTIN(NumberConstructor, ConstructorBuiltinsAssembler) { TNode<Context> context = CAST(Parameter(Descriptor::kContext)); diff --git a/chromium/v8/src/builtins/builtins-conversion-gen.cc b/chromium/v8/src/builtins/builtins-conversion-gen.cc index e524f39b5fd..54fa752969e 100644 --- a/chromium/v8/src/builtins/builtins-conversion-gen.cc +++ b/chromium/v8/src/builtins/builtins-conversion-gen.cc @@ -12,181 +12,6 @@ namespace v8 { namespace internal { -class ConversionBuiltinsAssembler : public CodeStubAssembler { - public: - explicit ConversionBuiltinsAssembler(compiler::CodeAssemblerState* state) - : CodeStubAssembler(state) {} - - protected: - void Generate_NonPrimitiveToPrimitive(TNode<Context> context, - TNode<Object> input, - ToPrimitiveHint hint); - - void Generate_OrdinaryToPrimitive(TNode<Context> context, TNode<Object> input, - OrdinaryToPrimitiveHint hint); -}; - -// ES6 section 7.1.1 ToPrimitive ( input [ , PreferredType ] ) -void ConversionBuiltinsAssembler::Generate_NonPrimitiveToPrimitive( - TNode<Context> context, TNode<Object> input, ToPrimitiveHint hint) { - // Lookup the @@toPrimitive property on the {input}. - TNode<Object> exotic_to_prim = - GetProperty(context, input, factory()->to_primitive_symbol()); - - // Check if {exotic_to_prim} is neither null nor undefined. - Label ordinary_to_primitive(this); - GotoIf(IsNullOrUndefined(exotic_to_prim), &ordinary_to_primitive); - { - // Invoke the {exotic_to_prim} method on the {input} with a string - // representation of the {hint}. - TNode<String> hint_string = - HeapConstant(factory()->ToPrimitiveHintString(hint)); - TNode<Object> result = Call(context, exotic_to_prim, input, hint_string); - - // Verify that the {result} is actually a primitive. - Label if_resultisprimitive(this), - if_resultisnotprimitive(this, Label::kDeferred); - GotoIf(TaggedIsSmi(result), &if_resultisprimitive); - TNode<Uint16T> result_instance_type = LoadInstanceType(CAST(result)); - Branch(IsPrimitiveInstanceType(result_instance_type), &if_resultisprimitive, - &if_resultisnotprimitive); - - BIND(&if_resultisprimitive); - { - // Just return the {result}. - Return(result); - } - - BIND(&if_resultisnotprimitive); - { - // Somehow the @@toPrimitive method on {input} didn't yield a primitive. - ThrowTypeError(context, MessageTemplate::kCannotConvertToPrimitive); - } - } - - // Convert using the OrdinaryToPrimitive algorithm instead. - BIND(&ordinary_to_primitive); - { - Callable callable = CodeFactory::OrdinaryToPrimitive( - isolate(), (hint == ToPrimitiveHint::kString) - ? OrdinaryToPrimitiveHint::kString - : OrdinaryToPrimitiveHint::kNumber); - TailCallStub(callable, context, input); - } -} - -TF_BUILTIN(NonPrimitiveToPrimitive_Default, ConversionBuiltinsAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> input = CAST(Parameter(Descriptor::kArgument)); - - Generate_NonPrimitiveToPrimitive(context, input, ToPrimitiveHint::kDefault); -} - -TF_BUILTIN(NonPrimitiveToPrimitive_Number, ConversionBuiltinsAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> input = CAST(Parameter(Descriptor::kArgument)); - - Generate_NonPrimitiveToPrimitive(context, input, ToPrimitiveHint::kNumber); -} - -TF_BUILTIN(NonPrimitiveToPrimitive_String, ConversionBuiltinsAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> input = CAST(Parameter(Descriptor::kArgument)); - - Generate_NonPrimitiveToPrimitive(context, input, ToPrimitiveHint::kString); -} - -TF_BUILTIN(StringToNumber, CodeStubAssembler) { - TNode<String> input = CAST(Parameter(Descriptor::kArgument)); - - Return(StringToNumber(input)); -} - -TF_BUILTIN(ToName, CodeStubAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> input = CAST(Parameter(Descriptor::kArgument)); - - TVARIABLE(Object, var_input, input); - Label loop(this, &var_input); - Goto(&loop); - BIND(&loop); - { - // Load the current {input} value. - TNode<Object> input = var_input.value(); - - // Dispatch based on the type of the {input.} - Label if_inputisbigint(this), if_inputisname(this), if_inputisnumber(this), - if_inputisoddball(this), if_inputisreceiver(this, Label::kDeferred); - GotoIf(TaggedIsSmi(input), &if_inputisnumber); - TNode<Uint16T> input_instance_type = LoadInstanceType(CAST(input)); - STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); - GotoIf(IsNameInstanceType(input_instance_type), &if_inputisname); - GotoIf(IsJSReceiverInstanceType(input_instance_type), &if_inputisreceiver); - GotoIf(IsHeapNumberInstanceType(input_instance_type), &if_inputisnumber); - Branch(IsBigIntInstanceType(input_instance_type), &if_inputisbigint, - &if_inputisoddball); - - BIND(&if_inputisbigint); - { - // We don't have a fast-path for BigInt currently, so just - // tail call to the %ToString runtime function here for now. - TailCallRuntime(Runtime::kToStringRT, context, input); - } - - BIND(&if_inputisname); - { - // The {input} is already a Name. - Return(input); - } - - BIND(&if_inputisnumber); - { - // Convert the String {input} to a Number. - TailCallBuiltin(Builtins::kNumberToString, context, input); - } - - BIND(&if_inputisoddball); - { - // Just return the {input}'s string representation. - CSA_ASSERT(this, IsOddballInstanceType(input_instance_type)); - Return(LoadObjectField(CAST(input), Oddball::kToStringOffset)); - } - - BIND(&if_inputisreceiver); - { - // Convert the JSReceiver {input} to a primitive first, - // and then run the loop again with the new {input}, - // which is then a primitive value. - var_input = CallBuiltin(Builtins::kNonPrimitiveToPrimitive_String, - context, input); - Goto(&loop); - } - } -} - -TF_BUILTIN(NonNumberToNumber, CodeStubAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<HeapObject> input = CAST(Parameter(Descriptor::kArgument)); - - Return(NonNumberToNumber(context, input)); -} - -TF_BUILTIN(NonNumberToNumeric, CodeStubAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<HeapObject> input = CAST(Parameter(Descriptor::kArgument)); - - Return(NonNumberToNumeric(context, input)); -} - -TF_BUILTIN(ToNumeric, CodeStubAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> input = CAST(Parameter(Descriptor::kArgument)); - - Return(Select<Numeric>( - IsNumber(input), [=] { return CAST(input); }, - [=] { return NonNumberToNumeric(context, CAST(input)); })); -} - // ES6 section 7.1.3 ToNumber ( argument ) TF_BUILTIN(ToNumber, CodeStubAssembler) { // TODO(solanes, v8:6949): Changing this to a TNode<Context> crashes with the @@ -206,93 +31,6 @@ TF_BUILTIN(ToNumberConvertBigInt, CodeStubAssembler) { Return(ToNumber(context, input, BigIntHandling::kConvertToNumber)); } -// ES section #sec-tostring-applied-to-the-number-type -TF_BUILTIN(NumberToString, CodeStubAssembler) { - TNode<Number> input = CAST(Parameter(Descriptor::kArgument)); - - Return(NumberToString(input)); -} - -// 7.1.1.1 OrdinaryToPrimitive ( O, hint ) -void ConversionBuiltinsAssembler::Generate_OrdinaryToPrimitive( - TNode<Context> context, TNode<Object> input, OrdinaryToPrimitiveHint hint) { - TVARIABLE(Object, var_result); - Label return_result(this, &var_result); - - Handle<String> method_names[2]; - switch (hint) { - case OrdinaryToPrimitiveHint::kNumber: - method_names[0] = factory()->valueOf_string(); - method_names[1] = factory()->toString_string(); - break; - case OrdinaryToPrimitiveHint::kString: - method_names[0] = factory()->toString_string(); - method_names[1] = factory()->valueOf_string(); - break; - } - for (Handle<String> name : method_names) { - // Lookup the {name} on the {input}. - TNode<Object> method = GetProperty(context, input, name); - - // Check if the {method} is callable. - Label if_methodiscallable(this), - if_methodisnotcallable(this, Label::kDeferred); - GotoIf(TaggedIsSmi(method), &if_methodisnotcallable); - TNode<Map> method_map = LoadMap(CAST(method)); - Branch(IsCallableMap(method_map), &if_methodiscallable, - &if_methodisnotcallable); - - BIND(&if_methodiscallable); - { - // Call the {method} on the {input}. - TNode<Object> result = Call(context, method, input); - var_result = result; - - // Return the {result} if it is a primitive. - GotoIf(TaggedIsSmi(result), &return_result); - TNode<Uint16T> result_instance_type = LoadInstanceType(CAST(result)); - GotoIf(IsPrimitiveInstanceType(result_instance_type), &return_result); - } - - // Just continue with the next {name} if the {method} is not callable. - Goto(&if_methodisnotcallable); - BIND(&if_methodisnotcallable); - } - - ThrowTypeError(context, MessageTemplate::kCannotConvertToPrimitive); - - BIND(&return_result); - Return(var_result.value()); -} - -TF_BUILTIN(OrdinaryToPrimitive_Number, ConversionBuiltinsAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> input = CAST(Parameter(Descriptor::kArgument)); - Generate_OrdinaryToPrimitive(context, input, - OrdinaryToPrimitiveHint::kNumber); -} - -TF_BUILTIN(OrdinaryToPrimitive_String, ConversionBuiltinsAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> input = CAST(Parameter(Descriptor::kArgument)); - Generate_OrdinaryToPrimitive(context, input, - OrdinaryToPrimitiveHint::kString); -} - -// ES6 section 7.1.2 ToBoolean ( argument ) -TF_BUILTIN(ToBoolean, CodeStubAssembler) { - TNode<Object> value = CAST(Parameter(Descriptor::kArgument)); - - Label return_true(this), return_false(this); - BranchIfToBooleanIsTrue(value, &return_true, &return_false); - - BIND(&return_true); - Return(TrueConstant()); - - BIND(&return_false); - Return(FalseConstant()); -} - // ES6 section 7.1.2 ToBoolean ( argument ) // Requires parameter on stack so that it can be used as a continuation from a // LAZY deopt. @@ -309,130 +47,6 @@ TF_BUILTIN(ToBooleanLazyDeoptContinuation, CodeStubAssembler) { Return(FalseConstant()); } -TF_BUILTIN(ToLength, CodeStubAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - - // We might need to loop once for ToNumber conversion. - TVARIABLE(Object, var_len, CAST(Parameter(Descriptor::kArgument))); - Label loop(this, &var_len); - Goto(&loop); - BIND(&loop); - { - // Shared entry points. - Label return_len(this), return_two53minus1(this, Label::kDeferred), - return_zero(this, Label::kDeferred); - - // Load the current {len} value. - TNode<Object> len = var_len.value(); - - // Check if {len} is a positive Smi. - GotoIf(TaggedIsPositiveSmi(len), &return_len); - - // Check if {len} is a (negative) Smi. - GotoIf(TaggedIsSmi(len), &return_zero); - - // Check if {len} is a HeapNumber. - TNode<HeapObject> len_heap_object = CAST(len); - Label if_lenisheapnumber(this), - if_lenisnotheapnumber(this, Label::kDeferred); - Branch(IsHeapNumber(len_heap_object), &if_lenisheapnumber, - &if_lenisnotheapnumber); - - BIND(&if_lenisheapnumber); - { - // Load the floating-point value of {len}. - TNode<Float64T> len_value = LoadHeapNumberValue(len_heap_object); - - // Check if {len} is not greater than zero. - GotoIfNot(Float64GreaterThan(len_value, Float64Constant(0.0)), - &return_zero); - - // Check if {len} is greater than or equal to 2^53-1. - GotoIf(Float64GreaterThanOrEqual(len_value, - Float64Constant(kMaxSafeInteger)), - &return_two53minus1); - - // Round the {len} towards -Infinity. - TNode<Float64T> value = Float64Floor(len_value); - TNode<Number> result = ChangeFloat64ToTagged(value); - Return(result); - } - - BIND(&if_lenisnotheapnumber); - { - // Need to convert {len} to a Number first. - var_len = CallBuiltin(Builtins::kNonNumberToNumber, context, len); - Goto(&loop); - } - - BIND(&return_len); - Return(var_len.value()); - - BIND(&return_two53minus1); - Return(NumberConstant(kMaxSafeInteger)); - - BIND(&return_zero); - Return(SmiConstant(0)); - } -} - -// ES6 section 7.1.13 ToObject (argument) -TF_BUILTIN(ToObject, CodeStubAssembler) { - Label if_smi(this, Label::kDeferred), if_jsreceiver(this), - if_noconstructor(this, Label::kDeferred), - if_wrapjs_primitive_wrapper(this); - - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> object = CAST(Parameter(Descriptor::kArgument)); - - TVARIABLE(IntPtrT, constructor_function_index_var); - - GotoIf(TaggedIsSmi(object), &if_smi); - - TNode<Map> map = LoadMap(CAST(object)); - TNode<Uint16T> instance_type = LoadMapInstanceType(map); - GotoIf(IsJSReceiverInstanceType(instance_type), &if_jsreceiver); - - TNode<IntPtrT> constructor_function_index = - LoadMapConstructorFunctionIndex(map); - GotoIf(WordEqual(constructor_function_index, - IntPtrConstant(Map::kNoConstructorFunctionIndex)), - &if_noconstructor); - constructor_function_index_var = constructor_function_index; - Goto(&if_wrapjs_primitive_wrapper); - - BIND(&if_smi); - constructor_function_index_var = - IntPtrConstant(Context::NUMBER_FUNCTION_INDEX); - Goto(&if_wrapjs_primitive_wrapper); - - BIND(&if_wrapjs_primitive_wrapper); - TNode<NativeContext> native_context = LoadNativeContext(context); - TNode<JSFunction> constructor = CAST(LoadContextElement( - native_context, constructor_function_index_var.value())); - TNode<Map> initial_map = LoadObjectField<Map>( - constructor, JSFunction::kPrototypeOrInitialMapOffset); - TNode<HeapObject> js_primitive_wrapper = - Allocate(JSPrimitiveWrapper::kHeaderSize); - StoreMapNoWriteBarrier(js_primitive_wrapper, initial_map); - StoreObjectFieldRoot(js_primitive_wrapper, - JSPrimitiveWrapper::kPropertiesOrHashOffset, - RootIndex::kEmptyFixedArray); - StoreObjectFieldRoot(js_primitive_wrapper, - JSPrimitiveWrapper::kElementsOffset, - RootIndex::kEmptyFixedArray); - StoreObjectField(js_primitive_wrapper, JSPrimitiveWrapper::kValueOffset, - object); - Return(js_primitive_wrapper); - - BIND(&if_noconstructor); - ThrowTypeError(context, MessageTemplate::kUndefinedOrNullToObject, - "ToObject"); - - BIND(&if_jsreceiver); - Return(object); -} - // ES6 section 12.5.5 typeof operator TF_BUILTIN(Typeof, CodeStubAssembler) { TNode<Object> object = CAST(Parameter(Descriptor::kObject)); diff --git a/chromium/v8/src/builtins/builtins-date-gen.cc b/chromium/v8/src/builtins/builtins-date-gen.cc index a3200330350..05fcc53f12b 100644 --- a/chromium/v8/src/builtins/builtins-date-gen.cc +++ b/chromium/v8/src/builtins/builtins-date-gen.cc @@ -197,7 +197,7 @@ TF_BUILTIN(DatePrototypeToPrimitive, CodeStubAssembler) { hint_is_invalid(this, Label::kDeferred); // Fast cases for internalized strings. - TNode<String> number_string = numberStringConstant(); + TNode<String> number_string = NumberStringConstant(); GotoIf(TaggedEqual(hint, number_string), &hint_is_number); TNode<String> default_string = DefaultStringConstant(); GotoIf(TaggedEqual(hint, default_string), &hint_is_string); diff --git a/chromium/v8/src/builtins/builtins-definitions.h b/chromium/v8/src/builtins/builtins-definitions.h index 84ddf55f6f4..b7286fa5657 100644 --- a/chromium/v8/src/builtins/builtins-definitions.h +++ b/chromium/v8/src/builtins/builtins-definitions.h @@ -51,12 +51,19 @@ namespace internal { ASM(Call_ReceiverIsNullOrUndefined, CallTrampoline) \ ASM(Call_ReceiverIsNotNullOrUndefined, CallTrampoline) \ ASM(Call_ReceiverIsAny, CallTrampoline) \ + TFC(Call_ReceiverIsNullOrUndefined_WithFeedback, \ + CallTrampoline_WithFeedback) \ + TFC(Call_ReceiverIsNotNullOrUndefined_WithFeedback, \ + CallTrampoline_WithFeedback) \ + TFC(Call_ReceiverIsAny_WithFeedback, CallTrampoline_WithFeedback) \ \ /* ES6 section 9.5.12[[Call]] ( thisArgument, argumentsList ) */ \ TFC(CallProxy, CallTrampoline) \ ASM(CallVarargs, CallVarargs) \ TFC(CallWithSpread, CallWithSpread) \ + TFC(CallWithSpread_WithFeedback, CallWithSpread_WithFeedback) \ TFC(CallWithArrayLike, CallWithArrayLike) \ + TFC(CallWithArrayLike_WithFeedback, CallWithArrayLike_WithFeedback) \ ASM(CallForwardVarargs, CallForwardVarargs) \ ASM(CallFunctionForwardVarargs, CallForwardVarargs) \ /* Call an API callback via a {FunctionTemplateInfo}, doing appropriate */ \ @@ -76,15 +83,20 @@ namespace internal { ASM(Construct, JSTrampoline) \ ASM(ConstructVarargs, ConstructVarargs) \ TFC(ConstructWithSpread, ConstructWithSpread) \ + TFC(ConstructWithSpread_WithFeedback, ConstructWithSpread_WithFeedback) \ TFC(ConstructWithArrayLike, ConstructWithArrayLike) \ + TFC(ConstructWithArrayLike_WithFeedback, \ + ConstructWithArrayLike_WithFeedback) \ ASM(ConstructForwardVarargs, ConstructForwardVarargs) \ ASM(ConstructFunctionForwardVarargs, ConstructForwardVarargs) \ + TFC(Construct_WithFeedback, Construct_WithFeedback) \ ASM(JSConstructStubGeneric, Dummy) \ ASM(JSBuiltinsConstructStub, Dummy) \ TFC(FastNewObject, FastNewObject) \ TFS(FastNewClosure, kSharedFunctionInfo, kFeedbackCell) \ TFC(FastNewFunctionContextEval, FastNewFunctionContext) \ TFC(FastNewFunctionContextFunction, FastNewFunctionContext) \ + TFS(CreateEmptyLiteralObject) \ TFS(CreateRegExpLiteral, kFeedbackVector, kSlot, kPattern, kFlags) \ TFS(CreateEmptyArrayLiteral, kFeedbackVector, kSlot) \ TFS(CreateShallowArrayLiteral, kFeedbackVector, kSlot, kConstantElements) \ @@ -185,22 +197,8 @@ namespace internal { ASM(HandleDebuggerStatement, ContextOnly) \ \ /* Type conversions */ \ - TFC(ToObject, TypeConversion) \ - TFC(ToBoolean, TypeConversion) \ - TFC(OrdinaryToPrimitive_Number, TypeConversion) \ - TFC(OrdinaryToPrimitive_String, TypeConversion) \ - TFC(NonPrimitiveToPrimitive_Default, TypeConversion) \ - TFC(NonPrimitiveToPrimitive_Number, TypeConversion) \ - TFC(NonPrimitiveToPrimitive_String, TypeConversion) \ - TFC(StringToNumber, TypeConversion) \ - TFC(ToName, TypeConversion) \ - TFC(NonNumberToNumber, TypeConversion) \ - TFC(NonNumberToNumeric, TypeConversion) \ TFC(ToNumber, TypeConversion) \ TFC(ToNumberConvertBigInt, TypeConversion) \ - TFC(ToNumeric, TypeConversion) \ - TFC(NumberToString, TypeConversion) \ - TFC(ToLength, TypeConversion) \ TFC(Typeof, Typeof) \ TFC(GetSuperConstructor, Typeof) \ TFC(BigIntToI64, BigIntToI64) \ @@ -503,11 +501,7 @@ namespace internal { CPP(FunctionConstructor) \ ASM(FunctionPrototypeApply, JSTrampoline) \ CPP(FunctionPrototypeBind) \ - /* ES6 #sec-function.prototype.bind */ \ - TFJ(FastFunctionPrototypeBind, kDontAdaptArgumentsSentinel) \ ASM(FunctionPrototypeCall, JSTrampoline) \ - /* ES6 #sec-function.prototype-@@hasinstance */ \ - TFJ(FunctionPrototypeHasInstance, 1, kReceiver, kV) \ /* ES6 #sec-function.prototype.tostring */ \ CPP(FunctionPrototypeToString) \ \ @@ -605,53 +599,42 @@ namespace internal { TFJ(MapIteratorPrototypeNext, 0, kReceiver) \ TFS(MapIteratorToList, kSource) \ \ - /* Number */ \ - TFC(AllocateHeapNumber, AllocateHeapNumber) \ /* ES #sec-number-constructor */ \ TFJ(NumberConstructor, kDontAdaptArgumentsSentinel) \ - /* ES6 #sec-number.isfinite */ \ - TFJ(NumberIsFinite, 1, kReceiver, kNumber) \ - /* ES6 #sec-number.isinteger */ \ - TFJ(NumberIsInteger, 1, kReceiver, kNumber) \ - /* ES6 #sec-number.isnan */ \ - TFJ(NumberIsNaN, 1, kReceiver, kNumber) \ - /* ES6 #sec-number.issafeinteger */ \ - TFJ(NumberIsSafeInteger, 1, kReceiver, kNumber) \ - /* ES6 #sec-number.parsefloat */ \ - TFJ(NumberParseFloat, 1, kReceiver, kString) \ - /* ES6 #sec-number.parseint */ \ - TFJ(NumberParseInt, 2, kReceiver, kString, kRadix) \ - TFS(ParseInt, kString, kRadix) \ CPP(NumberPrototypeToExponential) \ CPP(NumberPrototypeToFixed) \ CPP(NumberPrototypeToLocaleString) \ CPP(NumberPrototypeToPrecision) \ - /* ES6 #sec-number.prototype.valueof */ \ - TFJ(NumberPrototypeValueOf, 0, kReceiver) \ - TFC(Add, BinaryOp) \ - TFC(Subtract, BinaryOp) \ - TFC(Multiply, BinaryOp) \ - TFC(Divide, BinaryOp) \ - TFC(Modulus, BinaryOp) \ - TFC(Exponentiate, BinaryOp) \ - TFC(BitwiseAnd, BinaryOp) \ - TFC(BitwiseOr, BinaryOp) \ - TFC(BitwiseXor, BinaryOp) \ - TFC(ShiftLeft, BinaryOp) \ - TFC(ShiftRight, BinaryOp) \ - TFC(ShiftRightLogical, BinaryOp) \ - TFC(LessThan, Compare) \ - TFC(LessThanOrEqual, Compare) \ - TFC(GreaterThan, Compare) \ - TFC(GreaterThanOrEqual, Compare) \ - TFC(Equal, Compare) \ TFC(SameValue, Compare) \ TFC(SameValueNumbersOnly, Compare) \ - TFC(StrictEqual, Compare) \ - TFS(BitwiseNot, kValue) \ - TFS(Decrement, kValue) \ - TFS(Increment, kValue) \ - TFS(Negate, kValue) \ + \ + /* Binary ops with feedback collection */ \ + TFC(Add_WithFeedback, BinaryOp_WithFeedback) \ + TFC(Subtract_WithFeedback, BinaryOp_WithFeedback) \ + TFC(Multiply_WithFeedback, BinaryOp_WithFeedback) \ + TFC(Divide_WithFeedback, BinaryOp_WithFeedback) \ + TFC(Modulus_WithFeedback, BinaryOp_WithFeedback) \ + TFC(Exponentiate_WithFeedback, BinaryOp_WithFeedback) \ + TFC(BitwiseAnd_WithFeedback, BinaryOp_WithFeedback) \ + TFC(BitwiseOr_WithFeedback, BinaryOp_WithFeedback) \ + TFC(BitwiseXor_WithFeedback, BinaryOp_WithFeedback) \ + TFC(ShiftLeft_WithFeedback, BinaryOp_WithFeedback) \ + TFC(ShiftRight_WithFeedback, BinaryOp_WithFeedback) \ + TFC(ShiftRightLogical_WithFeedback, BinaryOp_WithFeedback) \ + \ + /* Compare ops with feedback collection */ \ + TFC(Equal_WithFeedback, Compare_WithFeedback) \ + TFC(StrictEqual_WithFeedback, Compare_WithFeedback) \ + TFC(LessThan_WithFeedback, Compare_WithFeedback) \ + TFC(GreaterThan_WithFeedback, Compare_WithFeedback) \ + TFC(LessThanOrEqual_WithFeedback, Compare_WithFeedback) \ + TFC(GreaterThanOrEqual_WithFeedback, Compare_WithFeedback) \ + \ + /* Unary ops with feedback collection */ \ + TFC(BitwiseNot_WithFeedback, UnaryOp_WithFeedback) \ + TFC(Decrement_WithFeedback, UnaryOp_WithFeedback) \ + TFC(Increment_WithFeedback, UnaryOp_WithFeedback) \ + TFC(Negate_WithFeedback, UnaryOp_WithFeedback) \ \ /* Object */ \ /* ES #sec-object-constructor */ \ @@ -813,12 +796,6 @@ namespace internal { TFJ(TypedArrayPrototypeByteOffset, 0, kReceiver) \ /* ES6 #sec-get-%typedarray%.prototype.length */ \ TFJ(TypedArrayPrototypeLength, 0, kReceiver) \ - /* ES6 #sec-%typedarray%.prototype.entries */ \ - TFJ(TypedArrayPrototypeEntries, 0, kReceiver) \ - /* ES6 #sec-%typedarray%.prototype.keys */ \ - TFJ(TypedArrayPrototypeKeys, 0, kReceiver) \ - /* ES6 #sec-%typedarray%.prototype.values */ \ - TFJ(TypedArrayPrototypeValues, 0, kReceiver) \ /* ES6 #sec-%typedarray%.prototype.copywithin */ \ CPP(TypedArrayPrototypeCopyWithin) \ /* ES6 #sec-%typedarray%.prototype.fill */ \ @@ -842,14 +819,8 @@ namespace internal { TFC(WasmFloat32ToNumber, WasmFloat32ToNumber) \ TFC(WasmFloat64ToNumber, WasmFloat64ToNumber) \ TFS(WasmAllocateArray, kMapIndex, kLength, kElementSize) \ - TFS(WasmAllocateStruct, kMapIndex) \ - TFC(WasmAtomicNotify, WasmAtomicNotify) \ TFC(WasmI32AtomicWait32, WasmI32AtomicWait32) \ - TFC(WasmI32AtomicWait64, WasmI32AtomicWait64) \ TFC(WasmI64AtomicWait32, WasmI64AtomicWait32) \ - TFC(WasmI64AtomicWait64, WasmI64AtomicWait64) \ - TFC(WasmTableInit, WasmTableInit) \ - TFC(WasmTableCopy, WasmTableCopy) \ \ /* WeakMap */ \ TFJ(WeakMapConstructor, kDontAdaptArgumentsSentinel) \ @@ -906,11 +877,11 @@ namespace internal { /* %AsyncFromSyncIteratorPrototype% */ \ /* See tc39.github.io/proposal-async-iteration/ */ \ /* #sec-%asyncfromsynciteratorprototype%-object) */ \ - TFJ(AsyncFromSyncIteratorPrototypeNext, 1, kReceiver, kValue) \ + TFJ(AsyncFromSyncIteratorPrototypeNext, kDontAdaptArgumentsSentinel) \ /* #sec-%asyncfromsynciteratorprototype%.throw */ \ - TFJ(AsyncFromSyncIteratorPrototypeThrow, 1, kReceiver, kReason) \ + TFJ(AsyncFromSyncIteratorPrototypeThrow, kDontAdaptArgumentsSentinel) \ /* #sec-%asyncfromsynciteratorprototype%.return */ \ - TFJ(AsyncFromSyncIteratorPrototypeReturn, 1, kReceiver, kValue) \ + TFJ(AsyncFromSyncIteratorPrototypeReturn, kDontAdaptArgumentsSentinel) \ /* #sec-async-iterator-value-unwrap-functions */ \ TFJ(AsyncIteratorValueUnwrap, 1, kReceiver, kValue) \ \ diff --git a/chromium/v8/src/builtins/builtins-descriptors.h b/chromium/v8/src/builtins/builtins-descriptors.h index 174b89795f5..c2eb44debea 100644 --- a/chromium/v8/src/builtins/builtins-descriptors.h +++ b/chromium/v8/src/builtins/builtins-descriptors.h @@ -13,34 +13,7 @@ namespace v8 { namespace internal { -#define REVERSE_0(a) a, -#define REVERSE_1(a, b) b, a, -#define REVERSE_2(a, b, c) c, b, a, -#define REVERSE_3(a, b, c, d) d, c, b, a, -#define REVERSE_4(a, b, c, d, e) e, d, c, b, a, -#define REVERSE_5(a, b, c, d, e, f) f, e, d, c, b, a, -#define REVERSE_6(a, b, c, d, e, f, g) g, f, e, d, c, b, a, -#define REVERSE_7(a, b, c, d, e, f, g, h) h, g, f, e, d, c, b, a, -#define REVERSE_8(a, b, c, d, e, f, g, h, i) i, h, g, f, e, d, c, b, a, -#define REVERSE_kDontAdaptArgumentsSentinel(...) -#define REVERSE(N, ...) REVERSE_##N(__VA_ARGS__) - // Define interface descriptors for builtins with JS linkage. -#ifdef V8_REVERSE_JSARGS -#define DEFINE_TFJ_INTERFACE_DESCRIPTOR(Name, Argc, ...) \ - struct Builtin_##Name##_InterfaceDescriptor { \ - enum ParameterIndices { \ - kJSTarget = compiler::CodeAssembler::kTargetParameterIndex, \ - REVERSE_##Argc(__VA_ARGS__) kJSNewTarget, \ - kJSActualArgumentsCount, \ - kContext, \ - kParameterCount, \ - }; \ - static_assert((Argc) == static_cast<uint16_t>(kParameterCount - 4), \ - "Inconsistent set of arguments"); \ - static_assert(kJSTarget == -1, "Unexpected kJSTarget index value"); \ - }; -#else #define DEFINE_TFJ_INTERFACE_DESCRIPTOR(Name, Argc, ...) \ struct Builtin_##Name##_InterfaceDescriptor { \ enum ParameterIndices { \ @@ -55,7 +28,6 @@ namespace internal { "Inconsistent set of arguments"); \ static_assert(kJSTarget == -1, "Unexpected kJSTarget index value"); \ }; -#endif // Define interface descriptors for builtins with StubCall linkage. #define DEFINE_TFC_INTERFACE_DESCRIPTOR(Name, InterfaceDescriptor) \ diff --git a/chromium/v8/src/builtins/builtins-function-gen.cc b/chromium/v8/src/builtins/builtins-function-gen.cc deleted file mode 100644 index 1d48ee84d1c..00000000000 --- a/chromium/v8/src/builtins/builtins-function-gen.cc +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2017 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "src/builtins/builtins-utils-gen.h" -#include "src/builtins/builtins.h" -#include "src/codegen/code-stub-assembler.h" -#include "src/execution/frame-constants.h" -#include "src/objects/api-callbacks.h" -#include "src/objects/descriptor-array.h" - -namespace v8 { -namespace internal { - -TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) { - Label slow(this); - - TNode<Int32T> argc = - UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount)); - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget)); - - CodeStubArguments args(this, argc); - - // Check that receiver has instance type of JS_FUNCTION_TYPE - TNode<Object> receiver = args.GetReceiver(); - GotoIf(TaggedIsSmi(receiver), &slow); - - TNode<Map> receiver_map = LoadMap(CAST(receiver)); - { - TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map); - GotoIfNot( - Word32Or(InstanceTypeEqual(instance_type, JS_FUNCTION_TYPE), - InstanceTypeEqual(instance_type, JS_BOUND_FUNCTION_TYPE)), - &slow); - } - - // Disallow binding of slow-mode functions. We need to figure out whether the - // length and name property are in the original state. - Comment("Disallow binding of slow-mode functions"); - GotoIf(IsDictionaryMap(receiver_map), &slow); - - // Check whether the length and name properties are still present as - // AccessorInfo objects. In that case, their value can be recomputed even if - // the actual value on the object changes. - Comment("Check descriptor array length"); - // Minimum descriptor array length required for fast path. - const int min_nof_descriptors = i::Max(JSFunction::kLengthDescriptorIndex, - JSFunction::kNameDescriptorIndex) + - 1; - TNode<Int32T> nof_descriptors = LoadNumberOfOwnDescriptors(receiver_map); - GotoIf(Int32LessThan(nof_descriptors, Int32Constant(min_nof_descriptors)), - &slow); - - // Check whether the length and name properties are still present as - // AccessorInfo objects. In that case, their value can be recomputed even if - // the actual value on the object changes. - Comment("Check name and length properties"); - { - TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map); - const int length_index = JSFunction::kLengthDescriptorIndex; - TNode<Name> maybe_length = - LoadKeyByDescriptorEntry(descriptors, length_index); - GotoIf(TaggedNotEqual(maybe_length, LengthStringConstant()), &slow); - - TNode<Object> maybe_length_accessor = - LoadValueByDescriptorEntry(descriptors, length_index); - GotoIf(TaggedIsSmi(maybe_length_accessor), &slow); - TNode<Map> length_value_map = LoadMap(CAST(maybe_length_accessor)); - GotoIfNot(IsAccessorInfoMap(length_value_map), &slow); - - const int name_index = JSFunction::kNameDescriptorIndex; - TNode<Name> maybe_name = LoadKeyByDescriptorEntry(descriptors, name_index); - GotoIf(TaggedNotEqual(maybe_name, NameStringConstant()), &slow); - - TNode<Object> maybe_name_accessor = - LoadValueByDescriptorEntry(descriptors, name_index); - GotoIf(TaggedIsSmi(maybe_name_accessor), &slow); - TNode<Map> name_value_map = LoadMap(CAST(maybe_name_accessor)); - GotoIfNot(IsAccessorInfoMap(name_value_map), &slow); - } - - // Choose the right bound function map based on whether the target is - // constructable. - Comment("Choose the right bound function map"); - TVARIABLE(Map, bound_function_map); - { - Label with_constructor(this); - TNode<NativeContext> native_context = LoadNativeContext(context); - - Label map_done(this, &bound_function_map); - GotoIf(IsConstructorMap(receiver_map), &with_constructor); - - bound_function_map = CAST(LoadContextElement( - native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX)); - Goto(&map_done); - - BIND(&with_constructor); - bound_function_map = CAST(LoadContextElement( - native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX)); - Goto(&map_done); - - BIND(&map_done); - } - - // Verify that __proto__ matches that of a the target bound function. - Comment("Verify that __proto__ matches target bound function"); - TNode<HeapObject> prototype = LoadMapPrototype(receiver_map); - TNode<HeapObject> expected_prototype = - LoadMapPrototype(bound_function_map.value()); - GotoIf(TaggedNotEqual(prototype, expected_prototype), &slow); - - // Allocate the arguments array. - Comment("Allocate the arguments array"); - TVARIABLE(FixedArray, argument_array); - { - Label empty_arguments(this); - Label arguments_done(this, &argument_array); - GotoIf(Uint32LessThanOrEqual(argc, Int32Constant(1)), &empty_arguments); - TNode<IntPtrT> elements_length = - Signed(ChangeUint32ToWord(Unsigned(Int32Sub(argc, Int32Constant(1))))); - argument_array = CAST(AllocateFixedArray(PACKED_ELEMENTS, elements_length, - kAllowLargeObjectAllocation)); - TVARIABLE(IntPtrT, index, IntPtrConstant(0)); - VariableList foreach_vars({&index}, zone()); - args.ForEach( - foreach_vars, - [&](TNode<Object> arg) { - StoreFixedArrayElement(argument_array.value(), index.value(), arg); - Increment(&index); - }, - IntPtrConstant(1)); - Goto(&arguments_done); - - BIND(&empty_arguments); - argument_array = EmptyFixedArrayConstant(); - Goto(&arguments_done); - - BIND(&arguments_done); - } - - // Determine bound receiver. - Comment("Determine bound receiver"); - TVARIABLE(Object, bound_receiver); - { - Label has_receiver(this); - Label receiver_done(this, &bound_receiver); - GotoIf(Word32NotEqual(argc, Int32Constant(0)), &has_receiver); - bound_receiver = UndefinedConstant(); - Goto(&receiver_done); - - BIND(&has_receiver); - bound_receiver = args.AtIndex(0); - Goto(&receiver_done); - - BIND(&receiver_done); - } - - // Allocate the resulting bound function. - Comment("Allocate the resulting bound function"); - { - TNode<HeapObject> bound_function = Allocate(JSBoundFunction::kHeaderSize); - StoreMapNoWriteBarrier(bound_function, bound_function_map.value()); - StoreObjectFieldNoWriteBarrier( - bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver); - StoreObjectFieldNoWriteBarrier(bound_function, - JSBoundFunction::kBoundThisOffset, - bound_receiver.value()); - StoreObjectFieldNoWriteBarrier(bound_function, - JSBoundFunction::kBoundArgumentsOffset, - argument_array.value()); - TNode<FixedArray> empty_fixed_array = EmptyFixedArrayConstant(); - StoreObjectFieldNoWriteBarrier( - bound_function, JSObject::kPropertiesOrHashOffset, empty_fixed_array); - StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kElementsOffset, - empty_fixed_array); - - args.PopAndReturn(bound_function); - } - - BIND(&slow); - { - // We are not using Parameter(Descriptor::kJSTarget) and loading the value - // from the current frame here in order to reduce register pressure on the - // fast path. - TNode<JSFunction> target = LoadTargetFromFrame(); - TailCallBuiltin(Builtins::kFunctionPrototypeBind, context, target, - new_target, argc); - } -} - -// ES6 #sec-function.prototype-@@hasinstance -TF_BUILTIN(FunctionPrototypeHasInstance, CodeStubAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> f = CAST(Parameter(Descriptor::kReceiver)); - TNode<Object> v = CAST(Parameter(Descriptor::kV)); - TNode<Oddball> result = OrdinaryHasInstance(context, f, v); - Return(result); -} - -} // namespace internal -} // namespace v8 diff --git a/chromium/v8/src/builtins/builtins-handler-gen.cc b/chromium/v8/src/builtins/builtins-handler-gen.cc index 0325ddab7c9..3f4a53a3461 100644 --- a/chromium/v8/src/builtins/builtins-handler-gen.cc +++ b/chromium/v8/src/builtins/builtins-handler-gen.cc @@ -9,6 +9,7 @@ #include "src/ic/ic.h" #include "src/ic/keyed-store-generic.h" #include "src/objects/objects-inl.h" +#include "torque-generated/exported-macros-assembler-tq.h" namespace v8 { namespace internal { @@ -78,37 +79,11 @@ TNode<Object> HandlerBuiltinsAssembler::EmitKeyedSloppyArguments( TNode<JSObject> receiver, TNode<Object> tagged_key, base::Optional<TNode<Object>> value, Label* bailout, ArgumentsAccessMode access_mode) { - // Mapped arguments are actual arguments. Unmapped arguments are values added - // to the arguments object after it was created for the call. Mapped arguments - // are stored in the context at indexes given by elements[key + 2]. Unmapped - // arguments are stored as regular indexed properties in the arguments array, - // held at elements[1]. See NewSloppyArguments() in runtime.cc for a detailed - // look at argument object construction. - // - // The sloppy arguments elements array has a special format: - // - // 0: context - // 1: unmapped arguments array - // 2: mapped_index0, - // 3: mapped_index1, - // ... - // - // length is 2 + min(number_of_actual_arguments, number_of_formal_arguments). - // If key + 2 >= elements.length then attempt to look in the unmapped - // arguments array (given by elements[1]) and return the value at key, missing - // to the runtime if the unmapped arguments array is not a fixed array or if - // key >= unmapped_arguments_array.length. - // - // Otherwise, t = elements[key + 2]. If t is the hole, then look up the value - // in the unmapped arguments array, as described above. Otherwise, t is a Smi - // index into the context array given at elements[0]. Return the value at - // context[t]. - GotoIfNot(TaggedIsSmi(tagged_key), bailout); TNode<IntPtrT> key = SmiUntag(CAST(tagged_key)); GotoIf(IntPtrLessThan(key, IntPtrConstant(0)), bailout); - TNode<FixedArray> elements = CAST(LoadElements(receiver)); + TNode<SloppyArgumentsElements> elements = CAST(LoadElements(receiver)); TNode<IntPtrT> elements_length = LoadAndUntagFixedArrayBaseLength(elements); TVARIABLE(Object, var_result); @@ -119,20 +94,18 @@ TNode<Object> HandlerBuiltinsAssembler::EmitKeyedSloppyArguments( access_mode == ArgumentsAccessMode::kHas); } Label if_mapped(this), if_unmapped(this), end(this, &var_result); - TNode<IntPtrT> intptr_two = IntPtrConstant(2); - TNode<IntPtrT> adjusted_length = IntPtrSub(elements_length, intptr_two); - GotoIf(UintPtrGreaterThanOrEqual(key, adjusted_length), &if_unmapped); + GotoIf(UintPtrGreaterThanOrEqual(key, elements_length), &if_unmapped); TNode<Object> mapped_index = - LoadFixedArrayElement(elements, IntPtrAdd(key, intptr_two)); + LoadSloppyArgumentsElementsMappedEntries(elements, key); Branch(TaggedEqual(mapped_index, TheHoleConstant()), &if_unmapped, &if_mapped); BIND(&if_mapped); { TNode<IntPtrT> mapped_index_intptr = SmiUntag(CAST(mapped_index)); - TNode<Context> the_context = CAST(LoadFixedArrayElement(elements, 0)); + TNode<Context> the_context = LoadSloppyArgumentsElementsContext(elements); if (access_mode == ArgumentsAccessMode::kLoad) { TNode<Object> result = LoadContextElement(the_context, mapped_index_intptr); @@ -151,7 +124,7 @@ TNode<Object> HandlerBuiltinsAssembler::EmitKeyedSloppyArguments( BIND(&if_unmapped); { TNode<HeapObject> backing_store_ho = - CAST(LoadFixedArrayElement(elements, 1)); + LoadSloppyArgumentsElementsArguments(elements); GotoIf(TaggedNotEqual(LoadMap(backing_store_ho), FixedArrayMapConstant()), bailout); TNode<FixedArray> backing_store = CAST(backing_store_ho); diff --git a/chromium/v8/src/builtins/builtins-internal-gen.cc b/chromium/v8/src/builtins/builtins-internal-gen.cc index 61f03b3f993..214f94802f3 100644 --- a/chromium/v8/src/builtins/builtins-internal-gen.cc +++ b/chromium/v8/src/builtins/builtins-internal-gen.cc @@ -72,7 +72,7 @@ TF_BUILTIN(GrowFastSmiOrObjectElements, CodeStubAssembler) { } TF_BUILTIN(NewArgumentsElements, CodeStubAssembler) { - TNode<IntPtrT> frame = UncheckedCast<IntPtrT>(Parameter(Descriptor::kFrame)); + TNode<RawPtrT> frame = UncheckedCast<RawPtrT>(Parameter(Descriptor::kFrame)); TNode<IntPtrT> length = SmiToIntPtr(Parameter(Descriptor::kLength)); TNode<IntPtrT> mapped_count = SmiToIntPtr(Parameter(Descriptor::kMappedCount)); @@ -127,10 +127,8 @@ TF_BUILTIN(NewArgumentsElements, CodeStubAssembler) { } BIND(&done_loop1); - // Compute the effective {offset} into the {frame}. - TNode<IntPtrT> offset = IntPtrAdd(length, IntPtrConstant(1)); - // Copy the parameters from {frame} (starting at {offset}) to {result}. + CodeStubArguments args(this, length, frame); Label loop2(this, &var_index), done_loop2(this); Goto(&loop2); BIND(&loop2); @@ -142,9 +140,7 @@ TF_BUILTIN(NewArgumentsElements, CodeStubAssembler) { GotoIf(IntPtrEqual(index, length), &done_loop2); // Load the parameter at the given {index}. - TNode<Object> value = BitcastWordToTagged( - Load(MachineType::Pointer(), frame, - TimesSystemPointerSize(IntPtrSub(offset, index)))); + TNode<Object> value = args.AtIndex(index); // Store the {value} into the {result}. StoreFixedArrayElement(result, index, value, SKIP_WRITE_BARRIER); @@ -221,9 +217,9 @@ class RecordWriteCodeStubAssembler : public CodeStubAssembler { TNode<BoolT> IsPageFlagSet(TNode<IntPtrT> object, int mask) { TNode<IntPtrT> page = PageFromAddress(object); - TNode<IntPtrT> flags = - UncheckedCast<IntPtrT>(Load(MachineType::Pointer(), page, - IntPtrConstant(MemoryChunk::kFlagsOffset))); + TNode<IntPtrT> flags = UncheckedCast<IntPtrT>( + Load(MachineType::Pointer(), page, + IntPtrConstant(BasicMemoryChunk::kFlagsOffset))); return WordNotEqual(WordAnd(flags, IntPtrConstant(mask)), IntPtrConstant(0)); } @@ -242,8 +238,8 @@ class RecordWriteCodeStubAssembler : public CodeStubAssembler { void GetMarkBit(TNode<IntPtrT> object, TNode<IntPtrT>* cell, TNode<IntPtrT>* mask) { TNode<IntPtrT> page = PageFromAddress(object); - TNode<IntPtrT> bitmap = - Load<IntPtrT>(page, IntPtrConstant(MemoryChunk::kMarkBitmapOffset)); + TNode<IntPtrT> bitmap = Load<IntPtrT>( + page, IntPtrConstant(BasicMemoryChunk::kMarkBitmapOffset)); { // Temp variable to calculate cell offset in bitmap. diff --git a/chromium/v8/src/builtins/builtins-microtask-queue-gen.cc b/chromium/v8/src/builtins/builtins-microtask-queue-gen.cc index e613ae9c08c..1da6f54c820 100644 --- a/chromium/v8/src/builtins/builtins-microtask-queue-gen.cc +++ b/chromium/v8/src/builtins/builtins-microtask-queue-gen.cc @@ -198,11 +198,18 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask( const TNode<Object> thenable = LoadObjectField( microtask, PromiseResolveThenableJobTask::kThenableOffset); + RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context, + CAST(promise_to_resolve)); + { ScopedExceptionHandler handler(this, &if_exception, &var_exception); CallBuiltin(Builtins::kPromiseResolveThenableJob, native_context, promise_to_resolve, thenable, then); } + + RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context, + CAST(promise_to_resolve)); + RewindEnteredContext(saved_entered_context_count); SetCurrentContext(current_context); Goto(&done); diff --git a/chromium/v8/src/builtins/builtins-number-gen.cc b/chromium/v8/src/builtins/builtins-number-gen.cc index 4513d73abc7..4e8bcae60be 100644 --- a/chromium/v8/src/builtins/builtins-number-gen.cc +++ b/chromium/v8/src/builtins/builtins-number-gen.cc @@ -6,6 +6,7 @@ #include "src/builtins/builtins.h" #include "src/codegen/code-stub-assembler.h" #include "src/ic/binary-op-assembler.h" +#include "src/ic/unary-op-assembler.h" namespace v8 { namespace internal { @@ -13,983 +14,108 @@ namespace internal { // ----------------------------------------------------------------------------- // ES6 section 20.1 Number Objects -class NumberBuiltinsAssembler : public CodeStubAssembler { - public: - explicit NumberBuiltinsAssembler(compiler::CodeAssemblerState* state) - : CodeStubAssembler(state) {} - - protected: - template <typename Descriptor> - void EmitBitwiseOp(Operation op) { - TNode<Object> left = CAST(Parameter(Descriptor::kLeft)); - TNode<Object> right = CAST(Parameter(Descriptor::kRight)); - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - - BinaryOpAssembler binop_asm(state()); - Return(binop_asm.Generate_BitwiseBinaryOp(op, left, right, context)); - } - - template <typename Descriptor> - void RelationalComparisonBuiltin(Operation op) { - TNode<Object> lhs = CAST(Parameter(Descriptor::kLeft)); - TNode<Object> rhs = CAST(Parameter(Descriptor::kRight)); - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - - Return(RelationalComparison(op, lhs, rhs, context)); - } - - template <typename Descriptor> - void UnaryOp(TVariable<Object>* var_input, Label* do_smi, Label* do_double, - TVariable<Float64T>* var_input_double, Label* do_bigint); - - template <typename Descriptor> - void BinaryOp(Label* smis, TVariable<Object>* var_left, - TVariable<Object>* var_right, Label* doubles, - TVariable<Float64T>* var_left_double, - TVariable<Float64T>* var_right_double, Label* bigints); -}; - -// ES6 #sec-number.isfinite -TF_BUILTIN(NumberIsFinite, CodeStubAssembler) { - TNode<Object> number = CAST(Parameter(Descriptor::kNumber)); - - Label return_true(this), return_false(this); - - // Check if {number} is a Smi. - GotoIf(TaggedIsSmi(number), &return_true); - - // Check if {number} is a HeapNumber. - TNode<HeapObject> number_heap_object = CAST(number); - GotoIfNot(IsHeapNumber(number_heap_object), &return_false); - - // Check if {number} contains a finite, non-NaN value. - TNode<Float64T> number_value = LoadHeapNumberValue(number_heap_object); - BranchIfFloat64IsNaN(Float64Sub(number_value, number_value), &return_false, - &return_true); - - BIND(&return_true); - Return(TrueConstant()); - - BIND(&return_false); - Return(FalseConstant()); -} - -TF_BUILTIN(AllocateHeapNumber, CodeStubAssembler) { - TNode<HeapNumber> result = AllocateHeapNumber(); - Return(result); -} - -// ES6 #sec-number.isinteger -TF_BUILTIN(NumberIsInteger, CodeStubAssembler) { - TNode<Object> number = CAST(Parameter(Descriptor::kNumber)); - Return(SelectBooleanConstant(IsInteger(number))); -} - -// ES6 #sec-number.isnan -TF_BUILTIN(NumberIsNaN, CodeStubAssembler) { - TNode<Object> number = CAST(Parameter(Descriptor::kNumber)); - - Label return_true(this), return_false(this); - - // Check if {number} is a Smi. - GotoIf(TaggedIsSmi(number), &return_false); - - // Check if {number} is a HeapNumber. - TNode<HeapObject> number_heap_object = CAST(number); - GotoIfNot(IsHeapNumber(number_heap_object), &return_false); - - // Check if {number} contains a NaN value. - TNode<Float64T> number_value = LoadHeapNumberValue(number_heap_object); - BranchIfFloat64IsNaN(number_value, &return_true, &return_false); - - BIND(&return_true); - Return(TrueConstant()); - - BIND(&return_false); - Return(FalseConstant()); -} - -// ES6 #sec-number.issafeinteger -TF_BUILTIN(NumberIsSafeInteger, CodeStubAssembler) { - TNode<Object> number = CAST(Parameter(Descriptor::kNumber)); - Return(SelectBooleanConstant(IsSafeInteger(number))); -} - -// ES6 #sec-number.parsefloat -TF_BUILTIN(NumberParseFloat, CodeStubAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - - // We might need to loop once for ToString conversion. - TVARIABLE(Object, var_input, CAST(Parameter(Descriptor::kString))); - Label loop(this, &var_input); - Goto(&loop); - BIND(&loop); - { - // Load the current {input} value. - TNode<Object> input = var_input.value(); - - // Check if the {input} is a HeapObject or a Smi. - Label if_inputissmi(this), if_inputisnotsmi(this); - Branch(TaggedIsSmi(input), &if_inputissmi, &if_inputisnotsmi); - - BIND(&if_inputissmi); - { - // The {input} is already a Number, no need to do anything. - Return(input); - } - - BIND(&if_inputisnotsmi); - { - // The {input} is a HeapObject, check if it's already a String. - TNode<HeapObject> input_heap_object = CAST(input); - Label if_inputisstring(this), if_inputisnotstring(this); - TNode<Map> input_map = LoadMap(input_heap_object); - TNode<Uint16T> input_instance_type = LoadMapInstanceType(input_map); - Branch(IsStringInstanceType(input_instance_type), &if_inputisstring, - &if_inputisnotstring); - - BIND(&if_inputisstring); - { - // The {input} is already a String, check if {input} contains - // a cached array index. - Label if_inputcached(this), if_inputnotcached(this); - TNode<Uint32T> input_hash = LoadNameHashField(CAST(input)); - Branch(IsClearWord32(input_hash, - Name::kDoesNotContainCachedArrayIndexMask), - &if_inputcached, &if_inputnotcached); - - BIND(&if_inputcached); - { - // Just return the {input}s cached array index. - TNode<UintPtrT> input_array_index = - DecodeWordFromWord32<String::ArrayIndexValueBits>(input_hash); - Return(SmiTag(Signed(input_array_index))); - } - - BIND(&if_inputnotcached); - { - // Need to fall back to the runtime to convert {input} to double. - Return(CallRuntime(Runtime::kStringParseFloat, context, input)); - } - } - - BIND(&if_inputisnotstring); - { - // The {input} is neither a String nor a Smi, check for HeapNumber. - Label if_inputisnumber(this), - if_inputisnotnumber(this, Label::kDeferred); - Branch(IsHeapNumberMap(input_map), &if_inputisnumber, - &if_inputisnotnumber); - - BIND(&if_inputisnumber); - { - // The {input} is already a Number, take care of -0. - Label if_inputiszero(this), if_inputisnotzero(this); - TNode<Float64T> input_value = LoadHeapNumberValue(input_heap_object); - Branch(Float64Equal(input_value, Float64Constant(0.0)), - &if_inputiszero, &if_inputisnotzero); - - BIND(&if_inputiszero); - Return(SmiConstant(0)); - - BIND(&if_inputisnotzero); - Return(input); - } - - BIND(&if_inputisnotnumber); - { - // Need to convert the {input} to String first. - // TODO(bmeurer): This could be more efficient if necessary. - var_input = CallBuiltin(Builtins::kToString, context, input); - Goto(&loop); - } - } - } - } -} - -// ES6 #sec-number.parseint -TF_BUILTIN(ParseInt, CodeStubAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> input = CAST(Parameter(Descriptor::kString)); - TNode<Object> radix = CAST(Parameter(Descriptor::kRadix)); - - // Check if {radix} is treated as 10 (i.e. undefined, 0 or 10). - Label if_radix10(this), if_generic(this, Label::kDeferred); - GotoIf(IsUndefined(radix), &if_radix10); - GotoIf(TaggedEqual(radix, SmiConstant(10)), &if_radix10); - GotoIf(TaggedEqual(radix, SmiConstant(0)), &if_radix10); - Goto(&if_generic); - - BIND(&if_radix10); - { - // Check if we can avoid the ToString conversion on {input}. - Label if_inputissmi(this), if_inputisheapnumber(this), - if_inputisstring(this); - GotoIf(TaggedIsSmi(input), &if_inputissmi); - TNode<Map> input_map = LoadMap(CAST(input)); - GotoIf(IsHeapNumberMap(input_map), &if_inputisheapnumber); - TNode<Uint16T> input_instance_type = LoadMapInstanceType(input_map); - Branch(IsStringInstanceType(input_instance_type), &if_inputisstring, - &if_generic); - - BIND(&if_inputissmi); - { - // Just return the {input}. - Return(input); - } - - BIND(&if_inputisheapnumber); - { - // Check if the {input} value is in Signed32 range. - Label if_inputissigned32(this); - TNode<Float64T> input_value = LoadHeapNumberValue(CAST(input)); - TNode<Int32T> input_value32 = - Signed(TruncateFloat64ToWord32(input_value)); - GotoIf(Float64Equal(input_value, ChangeInt32ToFloat64(input_value32)), - &if_inputissigned32); - - // Check if the absolute {input} value is in the [1,1<<31[ range. - // Take the generic path for the range [0,1[ because the result - // could be -0. - TNode<Float64T> input_value_abs = Float64Abs(input_value); - - GotoIfNot(Float64LessThan(input_value_abs, Float64Constant(1u << 31)), - &if_generic); - Branch(Float64LessThanOrEqual(Float64Constant(1), input_value_abs), - &if_inputissigned32, &if_generic); - - // Return the truncated int32 value, and return the tagged result. - BIND(&if_inputissigned32); - TNode<Number> result = ChangeInt32ToTagged(input_value32); - Return(result); - } - - BIND(&if_inputisstring); - { - // Check if the String {input} has a cached array index. - TNode<Uint32T> input_hash = LoadNameHashField(CAST(input)); - GotoIf(IsSetWord32(input_hash, Name::kDoesNotContainCachedArrayIndexMask), - &if_generic); - - // Return the cached array index as result. - TNode<UintPtrT> input_index = - DecodeWordFromWord32<String::ArrayIndexValueBits>(input_hash); - TNode<Smi> result = SmiTag(Signed(input_index)); - Return(result); - } - } - - BIND(&if_generic); - { - TNode<Object> result = - CallRuntime(Runtime::kStringParseInt, context, input, radix); - Return(result); - } -} - -// ES6 #sec-number.parseint -TF_BUILTIN(NumberParseInt, CodeStubAssembler) { +#define DEF_BINOP(Name, Generator) \ + TF_BUILTIN(Name, CodeStubAssembler) { \ + TNode<Object> lhs = CAST(Parameter(Descriptor::kLeft)); \ + TNode<Object> rhs = CAST(Parameter(Descriptor::kRight)); \ + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); \ + TNode<HeapObject> maybe_feedback_vector = \ + CAST(Parameter(Descriptor::kMaybeFeedbackVector)); \ + TNode<UintPtrT> slot = \ + UncheckedCast<UintPtrT>(Parameter(Descriptor::kSlot)); \ + \ + BinaryOpAssembler binop_asm(state()); \ + TNode<Object> result = binop_asm.Generator(context, lhs, rhs, slot, \ + maybe_feedback_vector, false); \ + \ + Return(result); \ + } +DEF_BINOP(Add_WithFeedback, Generate_AddWithFeedback) +DEF_BINOP(Subtract_WithFeedback, Generate_SubtractWithFeedback) +DEF_BINOP(Multiply_WithFeedback, Generate_MultiplyWithFeedback) +DEF_BINOP(Divide_WithFeedback, Generate_DivideWithFeedback) +DEF_BINOP(Modulus_WithFeedback, Generate_ModulusWithFeedback) +DEF_BINOP(Exponentiate_WithFeedback, Generate_ExponentiateWithFeedback) +DEF_BINOP(BitwiseOr_WithFeedback, Generate_BitwiseOrWithFeedback) +DEF_BINOP(BitwiseXor_WithFeedback, Generate_BitwiseXorWithFeedback) +DEF_BINOP(BitwiseAnd_WithFeedback, Generate_BitwiseAndWithFeedback) +DEF_BINOP(ShiftLeft_WithFeedback, Generate_ShiftLeftWithFeedback) +DEF_BINOP(ShiftRight_WithFeedback, Generate_ShiftRightWithFeedback) +DEF_BINOP(ShiftRightLogical_WithFeedback, + Generate_ShiftRightLogicalWithFeedback) +#undef DEF_BINOP + +#define DEF_UNOP(Name, Generator) \ + TF_BUILTIN(Name, CodeStubAssembler) { \ + TNode<Object> value = CAST(Parameter(Descriptor::kValue)); \ + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); \ + TNode<HeapObject> maybe_feedback_vector = \ + CAST(Parameter(Descriptor::kMaybeFeedbackVector)); \ + TNode<UintPtrT> slot = \ + UncheckedCast<UintPtrT>(Parameter(Descriptor::kSlot)); \ + \ + UnaryOpAssembler a(state()); \ + TNode<Object> result = \ + a.Generator(context, value, slot, maybe_feedback_vector); \ + \ + Return(result); \ + } +DEF_UNOP(BitwiseNot_WithFeedback, Generate_BitwiseNotWithFeedback) +DEF_UNOP(Decrement_WithFeedback, Generate_DecrementWithFeedback) +DEF_UNOP(Increment_WithFeedback, Generate_IncrementWithFeedback) +DEF_UNOP(Negate_WithFeedback, Generate_NegateWithFeedback) +#undef DEF_UNOP + +#define DEF_COMPARE(Name) \ + TF_BUILTIN(Name##_WithFeedback, CodeStubAssembler) { \ + TNode<Object> lhs = CAST(Parameter(Descriptor::kLeft)); \ + TNode<Object> rhs = CAST(Parameter(Descriptor::kRight)); \ + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); \ + TNode<HeapObject> maybe_feedback_vector = \ + CAST(Parameter(Descriptor::kMaybeFeedbackVector)); \ + TNode<UintPtrT> slot = \ + UncheckedCast<UintPtrT>(Parameter(Descriptor::kSlot)); \ + \ + TVARIABLE(Smi, var_type_feedback); \ + TNode<Oddball> result = RelationalComparison(Operation::k##Name, lhs, rhs, \ + context, &var_type_feedback); \ + UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector, slot); \ + \ + Return(result); \ + } +DEF_COMPARE(LessThan) +DEF_COMPARE(LessThanOrEqual) +DEF_COMPARE(GreaterThan) +DEF_COMPARE(GreaterThanOrEqual) +#undef DEF_COMPARE + +TF_BUILTIN(Equal_WithFeedback, CodeStubAssembler) { + TNode<Object> lhs = CAST(Parameter(Descriptor::kLeft)); + TNode<Object> rhs = CAST(Parameter(Descriptor::kRight)); TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> input = CAST(Parameter(Descriptor::kString)); - TNode<Object> radix = CAST(Parameter(Descriptor::kRadix)); - Return(CallBuiltin(Builtins::kParseInt, context, input, radix)); -} + TNode<HeapObject> maybe_feedback_vector = + CAST(Parameter(Descriptor::kMaybeFeedbackVector)); + TNode<UintPtrT> slot = UncheckedCast<UintPtrT>(Parameter(Descriptor::kSlot)); -// ES6 #sec-number.prototype.valueof -TF_BUILTIN(NumberPrototypeValueOf, CodeStubAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver)); + TVARIABLE(Smi, var_type_feedback); + TNode<Oddball> result = Equal(lhs, rhs, context, &var_type_feedback); + UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector, slot); - TNode<Object> result = ToThisValue(context, receiver, PrimitiveType::kNumber, - "Number.prototype.valueOf"); Return(result); } -class AddStubAssembler : public CodeStubAssembler { - public: - explicit AddStubAssembler(compiler::CodeAssemblerState* state) - : CodeStubAssembler(state) {} - - protected: - TNode<Object> ConvertReceiver(TNode<JSReceiver> js_receiver, - TNode<Context> context) { - // Call ToPrimitive explicitly without hint (whereas ToNumber - // would pass a "number" hint). - Callable callable = CodeFactory::NonPrimitiveToPrimitive(isolate()); - return CallStub(callable, context, js_receiver); - } - - void ConvertNonReceiverAndLoop(TVariable<Object>* var_value, Label* loop, - TNode<Context> context) { - *var_value = - CallBuiltin(Builtins::kNonNumberToNumeric, context, var_value->value()); - Goto(loop); - } - - void ConvertAndLoop(TVariable<Object>* var_value, - TNode<Uint16T> instance_type, Label* loop, - TNode<Context> context) { - Label is_not_receiver(this, Label::kDeferred); - GotoIfNot(IsJSReceiverInstanceType(instance_type), &is_not_receiver); - - *var_value = ConvertReceiver(CAST(var_value->value()), context); - Goto(loop); - - BIND(&is_not_receiver); - ConvertNonReceiverAndLoop(var_value, loop, context); - } -}; - -TF_BUILTIN(Add, AddStubAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TVARIABLE(Object, var_left, CAST(Parameter(Descriptor::kLeft))); - TVARIABLE(Object, var_right, CAST(Parameter(Descriptor::kRight))); - - // Shared entry for floating point addition. - Label do_double_add(this); - TVARIABLE(Float64T, var_left_double); - TVARIABLE(Float64T, var_right_double); - - // We might need to loop several times due to ToPrimitive, ToString and/or - // ToNumeric conversions. - Label loop(this, {&var_left, &var_right}), - string_add_convert_left(this, Label::kDeferred), - string_add_convert_right(this, Label::kDeferred), - do_bigint_add(this, Label::kDeferred); - Goto(&loop); - BIND(&loop); - { - TNode<Object> left = var_left.value(); - TNode<Object> right = var_right.value(); - - Label if_left_smi(this), if_left_heapobject(this); - Branch(TaggedIsSmi(left), &if_left_smi, &if_left_heapobject); - - BIND(&if_left_smi); - { - Label if_right_smi(this), if_right_heapobject(this); - Branch(TaggedIsSmi(right), &if_right_smi, &if_right_heapobject); - - BIND(&if_right_smi); - { - Label if_overflow(this); - TNode<Smi> left_smi = CAST(left); - TNode<Smi> right_smi = CAST(right); - TNode<Smi> result = TrySmiAdd(left_smi, right_smi, &if_overflow); - Return(result); - - BIND(&if_overflow); - { - var_left_double = SmiToFloat64(left_smi); - var_right_double = SmiToFloat64(right_smi); - Goto(&do_double_add); - } - } // if_right_smi - - BIND(&if_right_heapobject); - { - TNode<HeapObject> right_heap_object = CAST(right); - TNode<Map> right_map = LoadMap(right_heap_object); - - Label if_right_not_number(this, Label::kDeferred); - GotoIfNot(IsHeapNumberMap(right_map), &if_right_not_number); - - // {right} is a HeapNumber. - var_left_double = SmiToFloat64(CAST(left)); - var_right_double = LoadHeapNumberValue(right_heap_object); - Goto(&do_double_add); - - BIND(&if_right_not_number); - { - TNode<Uint16T> right_instance_type = LoadMapInstanceType(right_map); - GotoIf(IsStringInstanceType(right_instance_type), - &string_add_convert_left); - GotoIf(IsBigIntInstanceType(right_instance_type), &do_bigint_add); - ConvertAndLoop(&var_right, right_instance_type, &loop, context); - } - } // if_right_heapobject - } // if_left_smi - - BIND(&if_left_heapobject); - { - TNode<HeapObject> left_heap_object = CAST(left); - TNode<Map> left_map = LoadMap(left_heap_object); - Label if_right_smi(this), if_right_heapobject(this); - Branch(TaggedIsSmi(right), &if_right_smi, &if_right_heapobject); - - BIND(&if_right_smi); - { - Label if_left_not_number(this, Label::kDeferred); - GotoIfNot(IsHeapNumberMap(left_map), &if_left_not_number); - - // {left} is a HeapNumber, {right} is a Smi. - var_left_double = LoadHeapNumberValue(left_heap_object); - var_right_double = SmiToFloat64(CAST(right)); - Goto(&do_double_add); - - BIND(&if_left_not_number); - { - TNode<Uint16T> left_instance_type = LoadMapInstanceType(left_map); - GotoIf(IsStringInstanceType(left_instance_type), - &string_add_convert_right); - GotoIf(IsBigIntInstanceType(left_instance_type), &do_bigint_add); - // {left} is neither a Numeric nor a String, and {right} is a Smi. - ConvertAndLoop(&var_left, left_instance_type, &loop, context); - } - } // if_right_smi - - BIND(&if_right_heapobject); - { - TNode<HeapObject> right_heap_object = CAST(right); - TNode<Map> right_map = LoadMap(right_heap_object); - - Label if_left_number(this), if_left_not_number(this, Label::kDeferred); - Branch(IsHeapNumberMap(left_map), &if_left_number, &if_left_not_number); - - BIND(&if_left_number); - { - Label if_right_not_number(this, Label::kDeferred); - GotoIfNot(IsHeapNumberMap(right_map), &if_right_not_number); - - // Both {left} and {right} are HeapNumbers. - var_left_double = LoadHeapNumberValue(CAST(left)); - var_right_double = LoadHeapNumberValue(right_heap_object); - Goto(&do_double_add); - - BIND(&if_right_not_number); - { - TNode<Uint16T> right_instance_type = LoadMapInstanceType(right_map); - GotoIf(IsStringInstanceType(right_instance_type), - &string_add_convert_left); - GotoIf(IsBigIntInstanceType(right_instance_type), &do_bigint_add); - // {left} is a HeapNumber, {right} is neither Number nor String. - ConvertAndLoop(&var_right, right_instance_type, &loop, context); - } - } // if_left_number - - BIND(&if_left_not_number); - { - Label if_left_bigint(this); - TNode<Uint16T> left_instance_type = LoadMapInstanceType(left_map); - GotoIf(IsStringInstanceType(left_instance_type), - &string_add_convert_right); - TNode<Uint16T> right_instance_type = LoadMapInstanceType(right_map); - GotoIf(IsStringInstanceType(right_instance_type), - &string_add_convert_left); - GotoIf(IsBigIntInstanceType(left_instance_type), &if_left_bigint); - Label if_left_not_receiver(this, Label::kDeferred); - Label if_right_not_receiver(this, Label::kDeferred); - GotoIfNot(IsJSReceiverInstanceType(left_instance_type), - &if_left_not_receiver); - // {left} is a JSReceiver, convert it first. - var_left = ConvertReceiver(CAST(var_left.value()), context); - Goto(&loop); - - BIND(&if_left_bigint); - { - // {right} is a HeapObject, but not a String. Jump to - // {do_bigint_add} if {right} is already a Numeric. - GotoIf(IsBigIntInstanceType(right_instance_type), &do_bigint_add); - GotoIf(IsHeapNumberMap(right_map), &do_bigint_add); - ConvertAndLoop(&var_right, right_instance_type, &loop, context); - } - - BIND(&if_left_not_receiver); - GotoIfNot(IsJSReceiverInstanceType(right_instance_type), - &if_right_not_receiver); - // {left} is a Primitive, but {right} is a JSReceiver, so convert - // {right} with priority. - var_right = ConvertReceiver(CAST(var_right.value()), context); - Goto(&loop); - - BIND(&if_right_not_receiver); - // Neither {left} nor {right} are JSReceivers. - ConvertNonReceiverAndLoop(&var_left, &loop, context); - } - } // if_right_heapobject - } // if_left_heapobject - } - BIND(&string_add_convert_left); - { - // Convert {left} to a String and concatenate it with the String {right}. - TailCallBuiltin(Builtins::kStringAddConvertLeft, context, var_left.value(), - var_right.value()); - } - - BIND(&string_add_convert_right); - { - // Convert {right} to a String and concatenate it with the String {left}. - TailCallBuiltin(Builtins::kStringAddConvertRight, context, var_left.value(), - var_right.value()); - } - - BIND(&do_bigint_add); - { - TailCallBuiltin(Builtins::kBigIntAdd, context, var_left.value(), - var_right.value()); - } - - BIND(&do_double_add); - { - TNode<Float64T> value = - Float64Add(var_left_double.value(), var_right_double.value()); - Return(AllocateHeapNumberWithValue(value)); - } -} - -template <typename Descriptor> -void NumberBuiltinsAssembler::UnaryOp(TVariable<Object>* var_input, - Label* do_smi, Label* do_double, - TVariable<Float64T>* var_input_double, - Label* do_bigint) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - *var_input = CAST(Parameter(Descriptor::kValue)); - - // We might need to loop for ToNumeric conversion. - Label loop(this, {var_input}); - Goto(&loop); - BIND(&loop); - TNode<Object> input = var_input->value(); - - Label not_number(this); - GotoIf(TaggedIsSmi(input), do_smi); - TNode<HeapObject> input_heap_object = CAST(input); - GotoIfNot(IsHeapNumber(input_heap_object), ¬_number); - if (var_input_double != nullptr) { - *var_input_double = LoadHeapNumberValue(input_heap_object); - } - Goto(do_double); - - BIND(¬_number); - GotoIf(IsBigInt(input_heap_object), do_bigint); - *var_input = CallBuiltin(Builtins::kNonNumberToNumeric, context, input); - Goto(&loop); -} - -template <typename Descriptor> -void NumberBuiltinsAssembler::BinaryOp(Label* smis, TVariable<Object>* var_left, - TVariable<Object>* var_right, - Label* doubles, - TVariable<Float64T>* var_left_double, - TVariable<Float64T>* var_right_double, - Label* bigints) { - DCHECK_EQ(var_left_double == nullptr, var_right_double == nullptr); - - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - *var_left = CAST(Parameter(Descriptor::kLeft)); - *var_right = CAST(Parameter(Descriptor::kRight)); - - // We might need to loop for ToNumeric conversions. - Label loop(this, {var_left, var_right}); - Goto(&loop); - BIND(&loop); - - Label left_not_smi(this), right_not_smi(this); - Label left_not_number(this), right_not_number(this); - GotoIfNot(TaggedIsSmi(var_left->value()), &left_not_smi); - GotoIf(TaggedIsSmi(var_right->value()), smis); - - // At this point, var_left is a Smi but var_right is not. - TNode<Smi> var_left_smi = CAST(var_left->value()); - TNode<HeapObject> var_right_heap_object = CAST(var_right->value()); - GotoIfNot(IsHeapNumber(var_right_heap_object), &right_not_number); - if (var_left_double != nullptr) { - *var_left_double = SmiToFloat64(var_left_smi); - *var_right_double = LoadHeapNumberValue(var_right_heap_object); - } - Goto(doubles); - - BIND(&left_not_smi); - { - TNode<HeapObject> var_left_heap_object = CAST(var_left->value()); - GotoIfNot(IsHeapNumber(var_left_heap_object), &left_not_number); - GotoIfNot(TaggedIsSmi(var_right->value()), &right_not_smi); - - // At this point, var_left is a HeapNumber and var_right is a Smi. - if (var_left_double != nullptr) { - *var_left_double = LoadHeapNumberValue(var_left_heap_object); - *var_right_double = SmiToFloat64(CAST(var_right->value())); - } - Goto(doubles); - } - - BIND(&right_not_smi); - { - TNode<HeapObject> var_right_heap_object = CAST(var_right->value()); - GotoIfNot(IsHeapNumber(var_right_heap_object), &right_not_number); - if (var_left_double != nullptr) { - *var_left_double = LoadHeapNumberValue(CAST(var_left->value())); - *var_right_double = LoadHeapNumberValue(var_right_heap_object); - } - Goto(doubles); - } - - BIND(&left_not_number); - { - Label left_bigint(this); - GotoIf(IsBigInt(CAST(var_left->value())), &left_bigint); - *var_left = - CallBuiltin(Builtins::kNonNumberToNumeric, context, var_left->value()); - Goto(&loop); - - BIND(&left_bigint); - { - // Jump to {bigints} if {var_right} is already a Numeric. - GotoIf(TaggedIsSmi(var_right->value()), bigints); - TNode<HeapObject> var_right_heap_object = CAST(var_right->value()); - GotoIf(IsBigInt(var_right_heap_object), bigints); - GotoIf(IsHeapNumber(var_right_heap_object), bigints); - *var_right = CallBuiltin(Builtins::kNonNumberToNumeric, context, - var_right->value()); - Goto(&loop); - } - } - - BIND(&right_not_number); - { - GotoIf(IsBigInt(CAST(var_right->value())), bigints); - *var_right = - CallBuiltin(Builtins::kNonNumberToNumeric, context, var_right->value()); - Goto(&loop); - } -} - -TF_BUILTIN(Subtract, NumberBuiltinsAssembler) { - TVARIABLE(Object, var_left); - TVARIABLE(Object, var_right); - TVARIABLE(Float64T, var_left_double); - TVARIABLE(Float64T, var_right_double); - Label do_smi_sub(this), do_double_sub(this), do_bigint_sub(this); - - BinaryOp<Descriptor>(&do_smi_sub, &var_left, &var_right, &do_double_sub, - &var_left_double, &var_right_double, &do_bigint_sub); - - BIND(&do_smi_sub); - { - Label if_overflow(this); - TNode<Smi> var_left_smi = CAST(var_left.value()); - TNode<Smi> var_right_smi = CAST(var_right.value()); - TNode<Smi> result = TrySmiSub(var_left_smi, var_right_smi, &if_overflow); - Return(result); - - BIND(&if_overflow); - { - var_left_double = SmiToFloat64(var_left_smi); - var_right_double = SmiToFloat64(var_right_smi); - Goto(&do_double_sub); - } - } - - BIND(&do_double_sub); - { - TNode<Float64T> value = - Float64Sub(var_left_double.value(), var_right_double.value()); - Return(AllocateHeapNumberWithValue(value)); - } - - BIND(&do_bigint_sub); - { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TailCallBuiltin(Builtins::kBigIntSubtract, context, var_left.value(), - var_right.value()); - } -} - -TF_BUILTIN(BitwiseNot, NumberBuiltinsAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TVARIABLE(Object, var_input); - Label do_number(this), do_bigint(this); - - UnaryOp<Descriptor>(&var_input, &do_number, &do_number, nullptr, &do_bigint); - - BIND(&do_number); - { - TailCallBuiltin(Builtins::kBitwiseXor, context, var_input.value(), - SmiConstant(-1)); - } - - BIND(&do_bigint); - { - Return(CallRuntime(Runtime::kBigIntUnaryOp, context, var_input.value(), - SmiConstant(Operation::kBitwiseNot))); - } -} - -TF_BUILTIN(Decrement, NumberBuiltinsAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TVARIABLE(Object, var_input); - Label do_number(this), do_bigint(this); - - UnaryOp<Descriptor>(&var_input, &do_number, &do_number, nullptr, &do_bigint); - - BIND(&do_number); - { - TailCallBuiltin(Builtins::kSubtract, context, var_input.value(), - SmiConstant(1)); - } - - BIND(&do_bigint); - { - Return(CallRuntime(Runtime::kBigIntUnaryOp, context, var_input.value(), - SmiConstant(Operation::kDecrement))); - } -} - -TF_BUILTIN(Increment, NumberBuiltinsAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TVARIABLE(Object, var_input); - Label do_number(this), do_bigint(this); - - UnaryOp<Descriptor>(&var_input, &do_number, &do_number, nullptr, &do_bigint); - - BIND(&do_number); - { - TailCallBuiltin(Builtins::kAdd, context, var_input.value(), SmiConstant(1)); - } - - BIND(&do_bigint); - { - Return(CallRuntime(Runtime::kBigIntUnaryOp, context, var_input.value(), - SmiConstant(Operation::kIncrement))); - } -} - -TF_BUILTIN(Negate, NumberBuiltinsAssembler) { - TVARIABLE(Object, var_input); - TVARIABLE(Float64T, var_input_double); - Label do_smi(this), do_double(this), do_bigint(this); - - UnaryOp<Descriptor>(&var_input, &do_smi, &do_double, &var_input_double, - &do_bigint); - - BIND(&do_smi); - { Return(SmiMul(CAST(var_input.value()), SmiConstant(-1))); } - - BIND(&do_double); - { - TNode<Float64T> value = - Float64Mul(var_input_double.value(), Float64Constant(-1)); - Return(AllocateHeapNumberWithValue(value)); - } - - BIND(&do_bigint); - { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - Return(CallRuntime(Runtime::kBigIntUnaryOp, context, var_input.value(), - SmiConstant(Operation::kNegate))); - } -} - -TF_BUILTIN(Multiply, NumberBuiltinsAssembler) { - TVARIABLE(Object, var_left); - TVARIABLE(Object, var_right); - TVARIABLE(Float64T, var_left_double); - TVARIABLE(Float64T, var_right_double); - Label do_smi_mul(this), do_double_mul(this), do_bigint_mul(this); - - BinaryOp<Descriptor>(&do_smi_mul, &var_left, &var_right, &do_double_mul, - &var_left_double, &var_right_double, &do_bigint_mul); - - BIND(&do_smi_mul); - // The result is not necessarily a smi, in case of overflow. - Return(SmiMul(CAST(var_left.value()), CAST(var_right.value()))); - - BIND(&do_double_mul); - TNode<Float64T> value = - Float64Mul(var_left_double.value(), var_right_double.value()); - Return(AllocateHeapNumberWithValue(value)); - - BIND(&do_bigint_mul); - { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(), - var_right.value(), SmiConstant(Operation::kMultiply))); - } -} - -TF_BUILTIN(Divide, NumberBuiltinsAssembler) { - TVARIABLE(Object, var_left); - TVARIABLE(Object, var_right); - TVARIABLE(Float64T, var_left_double); - TVARIABLE(Float64T, var_right_double); - Label do_smi_div(this), do_double_div(this), do_bigint_div(this); - - BinaryOp<Descriptor>(&do_smi_div, &var_left, &var_right, &do_double_div, - &var_left_double, &var_right_double, &do_bigint_div); - - BIND(&do_smi_div); - { - // TODO(jkummerow): Consider just always doing a double division. - Label bailout(this); - TNode<Smi> dividend = CAST(var_left.value()); - TNode<Smi> divisor = CAST(var_right.value()); - - // Do floating point division if {divisor} is zero. - GotoIf(SmiEqual(divisor, SmiConstant(0)), &bailout); - - // Do floating point division if {dividend} is zero and {divisor} is - // negative. - Label dividend_is_zero(this), dividend_is_not_zero(this); - Branch(SmiEqual(dividend, SmiConstant(0)), ÷nd_is_zero, - ÷nd_is_not_zero); - - BIND(÷nd_is_zero); - { - GotoIf(SmiLessThan(divisor, SmiConstant(0)), &bailout); - Goto(÷nd_is_not_zero); - } - BIND(÷nd_is_not_zero); - - TNode<Int32T> untagged_divisor = SmiToInt32(divisor); - TNode<Int32T> untagged_dividend = SmiToInt32(dividend); - - // Do floating point division if {dividend} is kMinInt (or kMinInt - 1 - // if the Smi size is 31) and {divisor} is -1. - Label divisor_is_minus_one(this), divisor_is_not_minus_one(this); - Branch(Word32Equal(untagged_divisor, Int32Constant(-1)), - &divisor_is_minus_one, &divisor_is_not_minus_one); - - BIND(&divisor_is_minus_one); - { - GotoIf(Word32Equal( - untagged_dividend, - Int32Constant(kSmiValueSize == 32 ? kMinInt : (kMinInt >> 1))), - &bailout); - Goto(&divisor_is_not_minus_one); - } - BIND(&divisor_is_not_minus_one); - - // TODO(epertoso): consider adding a machine instruction that returns - // both the result and the remainder. - TNode<Int32T> untagged_result = - Int32Div(untagged_dividend, untagged_divisor); - TNode<Int32T> truncated = Int32Mul(untagged_result, untagged_divisor); - // Do floating point division if the remainder is not 0. - GotoIf(Word32NotEqual(untagged_dividend, truncated), &bailout); - Return(SmiFromInt32(untagged_result)); - - // Bailout: convert {dividend} and {divisor} to double and do double - // division. - BIND(&bailout); - { - var_left_double = SmiToFloat64(dividend); - var_right_double = SmiToFloat64(divisor); - Goto(&do_double_div); - } - } - - BIND(&do_double_div); - { - TNode<Float64T> value = - Float64Div(var_left_double.value(), var_right_double.value()); - Return(AllocateHeapNumberWithValue(value)); - } - - BIND(&do_bigint_div); - { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(), - var_right.value(), SmiConstant(Operation::kDivide))); - } -} - -TF_BUILTIN(Modulus, NumberBuiltinsAssembler) { - TVARIABLE(Object, var_left); - TVARIABLE(Object, var_right); - TVARIABLE(Float64T, var_left_double); - TVARIABLE(Float64T, var_right_double); - Label do_smi_mod(this), do_double_mod(this), do_bigint_mod(this); - - BinaryOp<Descriptor>(&do_smi_mod, &var_left, &var_right, &do_double_mod, - &var_left_double, &var_right_double, &do_bigint_mod); - - BIND(&do_smi_mod); - Return(SmiMod(CAST(var_left.value()), CAST(var_right.value()))); - - BIND(&do_double_mod); - TNode<Float64T> value = - Float64Mod(var_left_double.value(), var_right_double.value()); - Return(AllocateHeapNumberWithValue(value)); - - BIND(&do_bigint_mod); - { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(), - var_right.value(), SmiConstant(Operation::kModulus))); - } -} - -TF_BUILTIN(Exponentiate, NumberBuiltinsAssembler) { - TVARIABLE(Object, var_left); - TVARIABLE(Object, var_right); - Label do_number_exp(this), do_bigint_exp(this); - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - - BinaryOp<Descriptor>(&do_number_exp, &var_left, &var_right, &do_number_exp, - nullptr, nullptr, &do_bigint_exp); - - BIND(&do_number_exp); - { Return(MathPowImpl(context, var_left.value(), var_right.value())); } - - BIND(&do_bigint_exp); - Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(), - var_right.value(), SmiConstant(Operation::kExponentiate))); -} - -TF_BUILTIN(ShiftLeft, NumberBuiltinsAssembler) { - EmitBitwiseOp<Descriptor>(Operation::kShiftLeft); -} - -TF_BUILTIN(ShiftRight, NumberBuiltinsAssembler) { - EmitBitwiseOp<Descriptor>(Operation::kShiftRight); -} - -TF_BUILTIN(ShiftRightLogical, NumberBuiltinsAssembler) { - EmitBitwiseOp<Descriptor>(Operation::kShiftRightLogical); -} - -TF_BUILTIN(BitwiseAnd, NumberBuiltinsAssembler) { - EmitBitwiseOp<Descriptor>(Operation::kBitwiseAnd); -} - -TF_BUILTIN(BitwiseOr, NumberBuiltinsAssembler) { - EmitBitwiseOp<Descriptor>(Operation::kBitwiseOr); -} - -TF_BUILTIN(BitwiseXor, NumberBuiltinsAssembler) { - EmitBitwiseOp<Descriptor>(Operation::kBitwiseXor); -} - -TF_BUILTIN(LessThan, NumberBuiltinsAssembler) { - RelationalComparisonBuiltin<Descriptor>(Operation::kLessThan); -} - -TF_BUILTIN(LessThanOrEqual, NumberBuiltinsAssembler) { - RelationalComparisonBuiltin<Descriptor>(Operation::kLessThanOrEqual); -} - -TF_BUILTIN(GreaterThan, NumberBuiltinsAssembler) { - RelationalComparisonBuiltin<Descriptor>(Operation::kGreaterThan); -} - -TF_BUILTIN(GreaterThanOrEqual, NumberBuiltinsAssembler) { - RelationalComparisonBuiltin<Descriptor>(Operation::kGreaterThanOrEqual); -} - -TF_BUILTIN(Equal, CodeStubAssembler) { +TF_BUILTIN(StrictEqual_WithFeedback, CodeStubAssembler) { TNode<Object> lhs = CAST(Parameter(Descriptor::kLeft)); TNode<Object> rhs = CAST(Parameter(Descriptor::kRight)); - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<HeapObject> maybe_feedback_vector = + CAST(Parameter(Descriptor::kMaybeFeedbackVector)); + TNode<UintPtrT> slot = UncheckedCast<UintPtrT>(Parameter(Descriptor::kSlot)); - Return(Equal(lhs, rhs, context)); -} + TVARIABLE(Smi, var_type_feedback); + TNode<Oddball> result = StrictEqual(lhs, rhs, &var_type_feedback); + UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector, slot); -TF_BUILTIN(StrictEqual, CodeStubAssembler) { - TNode<Object> lhs = CAST(Parameter(Descriptor::kLeft)); - TNode<Object> rhs = CAST(Parameter(Descriptor::kRight)); - - Return(StrictEqual(lhs, rhs)); + Return(result); } } // namespace internal diff --git a/chromium/v8/src/builtins/builtins-object-gen.cc b/chromium/v8/src/builtins/builtins-object-gen.cc index 06045495581..43a0a6953e8 100644 --- a/chromium/v8/src/builtins/builtins-object-gen.cc +++ b/chromium/v8/src/builtins/builtins-object-gen.cc @@ -314,7 +314,8 @@ TNode<JSArray> ObjectEntriesValuesBuiltinsAssembler::FastGetOwnValuesOrEntries( TNode<JSArray> array; TNode<FixedArrayBase> elements; std::tie(array, elements) = AllocateUninitializedJSArrayWithElements( - PACKED_ELEMENTS, array_map, SmiConstant(2), {}, IntPtrConstant(2)); + PACKED_ELEMENTS, array_map, SmiConstant(2), base::nullopt, + IntPtrConstant(2)); StoreFixedArrayElement(CAST(elements), 0, next_key, SKIP_WRITE_BARRIER); StoreFixedArrayElement(CAST(elements), 1, value, SKIP_WRITE_BARRIER); value = TNode<JSArray>::UncheckedCast(array); @@ -499,7 +500,7 @@ TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) { LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context); TNode<Smi> array_length = SmiTag(Signed(object_enum_length)); std::tie(array, elements) = AllocateUninitializedJSArrayWithElements( - PACKED_ELEMENTS, array_map, array_length, {}, + PACKED_ELEMENTS, array_map, array_length, base::nullopt, Signed(object_enum_length)); CopyFixedArrayElements(PACKED_ELEMENTS, object_enum_keys, elements, object_enum_length, SKIP_WRITE_BARRIER); @@ -595,7 +596,7 @@ TF_BUILTIN(ObjectGetOwnPropertyNames, ObjectBuiltinsAssembler) { TNode<JSArray> array; TNode<FixedArrayBase> elements; std::tie(array, elements) = AllocateUninitializedJSArrayWithElements( - PACKED_ELEMENTS, array_map, array_length, {}, + PACKED_ELEMENTS, array_map, array_length, base::nullopt, Signed(object_enum_length)); CopyFixedArrayElements(PACKED_ELEMENTS, object_enum_keys, elements, object_enum_length, SKIP_WRITE_BARRIER); diff --git a/chromium/v8/src/builtins/builtins-promise.h b/chromium/v8/src/builtins/builtins-promise.h index fd938ff8418..a775ea20411 100644 --- a/chromium/v8/src/builtins/builtins-promise.h +++ b/chromium/v8/src/builtins/builtins-promise.h @@ -35,7 +35,7 @@ class PromiseBuiltins { kPromiseAllResolveElementCapabilitySlot, // Values array from Promise.all - kPromiseAllResolveElementValuesArraySlot, + kPromiseAllResolveElementValuesSlot, kPromiseAllResolveElementLength }; @@ -48,7 +48,7 @@ class PromiseBuiltins { kPromiseAnyRejectElementCapabilitySlot, // errors array from Promise.any - kPromiseAnyRejectElementErrorsArraySlot, + kPromiseAnyRejectElementErrorsSlot, kPromiseAnyRejectElementLength }; diff --git a/chromium/v8/src/builtins/builtins-regexp-gen.cc b/chromium/v8/src/builtins/builtins-regexp-gen.cc index b9c1b8980ea..584111cc760 100644 --- a/chromium/v8/src/builtins/builtins-regexp-gen.cc +++ b/chromium/v8/src/builtins/builtins-regexp-gen.cc @@ -89,7 +89,7 @@ TNode<JSRegExpResult> RegExpBuiltinsAssembler::AllocateRegExpResult( const ElementsKind elements_kind = PACKED_ELEMENTS; TNode<Map> map = CAST(LoadContextElement(LoadNativeContext(context), Context::REGEXP_RESULT_MAP_INDEX)); - TNode<AllocationSite> no_allocation_site = {}; + base::Optional<TNode<AllocationSite>> no_allocation_site = base::nullopt; TNode<IntPtrT> length_intptr = SmiUntag(length); // Note: The returned `elements` may be in young large object space, but @@ -1354,9 +1354,7 @@ TNode<JSArray> RegExpBuiltinsAssembler::RegExpPrototypeSplitBody( const TNode<IntPtrT> int_limit = SmiUntag(limit); const ElementsKind kind = PACKED_ELEMENTS; - const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; - TNode<AllocationSite> allocation_site = {}; const TNode<NativeContext> native_context = LoadNativeContext(context); TNode<Map> array_map = LoadJSArrayElementsMap(kind, native_context); @@ -1396,6 +1394,7 @@ TNode<JSArray> RegExpBuiltinsAssembler::RegExpPrototypeSplitBody( { TNode<Smi> length = SmiConstant(1); TNode<IntPtrT> capacity = IntPtrConstant(1); + base::Optional<TNode<AllocationSite>> allocation_site = base::nullopt; var_result = AllocateJSArray(kind, array_map, capacity, length, allocation_site); @@ -1508,10 +1507,10 @@ TNode<JSArray> RegExpBuiltinsAssembler::RegExpPrototypeSplitBody( const TNode<IntPtrT> reg = var_reg.value(); const TNode<Object> from = LoadFixedArrayElement( match_indices, reg, - RegExpMatchInfo::kFirstCaptureIndex * kTaggedSize, mode); + RegExpMatchInfo::kFirstCaptureIndex * kTaggedSize); const TNode<Smi> to = CAST(LoadFixedArrayElement( match_indices, reg, - (RegExpMatchInfo::kFirstCaptureIndex + 1) * kTaggedSize, mode)); + (RegExpMatchInfo::kFirstCaptureIndex + 1) * kTaggedSize)); Label select_capture(this), select_undefined(this), store_value(this); TVARIABLE(Object, var_value); @@ -1570,6 +1569,7 @@ TNode<JSArray> RegExpBuiltinsAssembler::RegExpPrototypeSplitBody( { TNode<Smi> length = SmiZero(); TNode<IntPtrT> capacity = IntPtrZero(); + base::Optional<TNode<AllocationSite>> allocation_site = base::nullopt; var_result = AllocateJSArray(kind, array_map, capacity, length, allocation_site); Goto(&done); diff --git a/chromium/v8/src/builtins/builtins-string-gen.cc b/chromium/v8/src/builtins/builtins-string-gen.cc index 7ccb99792ed..9920369136a 100644 --- a/chromium/v8/src/builtins/builtins-string-gen.cc +++ b/chromium/v8/src/builtins/builtins-string-gen.cc @@ -1164,10 +1164,11 @@ void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol( DescriptorIndexNameValue additional_property_to_check, const NodeFunction0& regexp_call, const NodeFunction1& generic_call) { Label out(this); + Label get_property_lookup(this); - // Smis definitely don't have an attached symbol. - GotoIf(TaggedIsSmi(object), &out); - TNode<HeapObject> heap_object = CAST(object); + // Smis have to go through the GetProperty lookup in case Number.prototype or + // Object.prototype was modified. + GotoIf(TaggedIsSmi(object), &get_property_lookup); // Take the fast path for RegExps. // There's two conditions: {object} needs to be a fast regexp, and @@ -1176,6 +1177,8 @@ void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol( { Label stub_call(this), slow_lookup(this); + TNode<HeapObject> heap_object = CAST(object); + GotoIf(TaggedIsSmi(maybe_string), &slow_lookup); GotoIfNot(IsString(CAST(maybe_string)), &slow_lookup); @@ -1196,10 +1199,10 @@ void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol( regexp_call(); BIND(&slow_lookup); + // Special case null and undefined to skip the property lookup. + Branch(IsNullOrUndefined(heap_object), &out, &get_property_lookup); } - GotoIf(IsNullOrUndefined(heap_object), &out); - // Fall back to a slow lookup of {heap_object[symbol]}. // // The spec uses GetMethod({heap_object}, {symbol}), which has a few quirks: @@ -1208,7 +1211,8 @@ void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol( // We handle the former by jumping to {out} for null values as well, while // the latter is already handled by the Call({maybe_func}) operation. - const TNode<Object> maybe_func = GetProperty(context, heap_object, symbol); + BIND(&get_property_lookup); + const TNode<Object> maybe_func = GetProperty(context, object, symbol); GotoIf(IsUndefined(maybe_func), &out); GotoIf(IsNull(maybe_func), &out); diff --git a/chromium/v8/src/builtins/builtins-string.cc b/chromium/v8/src/builtins/builtins-string.cc index 8a897765c83..df5ba93a59e 100644 --- a/chromium/v8/src/builtins/builtins-string.cc +++ b/chromium/v8/src/builtins/builtins-string.cc @@ -40,14 +40,16 @@ bool IsValidCodePoint(Isolate* isolate, Handle<Object> value) { return true; } +static constexpr uc32 kInvalidCodePoint = static_cast<uc32>(-1); + uc32 NextCodePoint(Isolate* isolate, BuiltinArguments args, int index) { Handle<Object> value = args.at(1 + index); - ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value, - Object::ToNumber(isolate, value), -1); + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + isolate, value, Object::ToNumber(isolate, value), kInvalidCodePoint); if (!IsValidCodePoint(isolate, value)) { isolate->Throw(*isolate->factory()->NewRangeError( MessageTemplate::kInvalidCodePoint, value)); - return -1; + return kInvalidCodePoint; } return DoubleToUint32(value->Number()); } @@ -69,7 +71,7 @@ BUILTIN(StringFromCodePoint) { int index; for (index = 0; index < length; index++) { code = NextCodePoint(isolate, args, index); - if (code < 0) { + if (code == kInvalidCodePoint) { return ReadOnlyRoots(isolate).exception(); } if (code > String::kMaxOneByteCharCode) { @@ -99,7 +101,7 @@ BUILTIN(StringFromCodePoint) { break; } code = NextCodePoint(isolate, args, index); - if (code < 0) { + if (code == kInvalidCodePoint) { return ReadOnlyRoots(isolate).exception(); } } diff --git a/chromium/v8/src/builtins/builtins-string.tq b/chromium/v8/src/builtins/builtins-string.tq index a4edc94418c..6ec7bc9d0ac 100644 --- a/chromium/v8/src/builtins/builtins-string.tq +++ b/chromium/v8/src/builtins/builtins-string.tq @@ -5,6 +5,43 @@ #include 'src/builtins/builtins-string-gen.h' namespace string { + +// TODO(bbudge) Remove the 'RT' suffix on this runtime function. +extern transitioning runtime ToStringRT(Context, JSAny): String; + +@export +transitioning macro ToStringImpl(context: Context, o: JSAny): String { + let result: JSAny = o; + while (true) { + typeswitch (result) { + case (num: Number): { + return NumberToString(num); + } + case (str: String): { + return str; + } + case (oddball: Oddball): { + return oddball.to_string; + } + case (JSReceiver): { + result = NonPrimitiveToPrimitive_String(context, result); + continue; + } + case (Symbol): { + ThrowTypeError(MessageTemplate::kSymbolToString); + } + case (JSAny): { + return ToStringRT(context, o); + } + } + } + unreachable; +} + +transitioning builtin ToString(context: Context, o: JSAny): String { + return ToStringImpl(context, o); +} + extern macro StringBuiltinsAssembler::SubString( String, uintptr, uintptr): String; diff --git a/chromium/v8/src/builtins/builtins-typed-array-gen.cc b/chromium/v8/src/builtins/builtins-typed-array-gen.cc index a6d3887ad31..b359b438c74 100644 --- a/chromium/v8/src/builtins/builtins-typed-array-gen.cc +++ b/chromium/v8/src/builtins/builtins-typed-array-gen.cc @@ -505,49 +505,5 @@ TF_BUILTIN(TypedArrayPrototypeToStringTag, TypedArrayBuiltinsAssembler) { BIND(&return_undefined); Return(UndefinedConstant()); } - -void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeIterationMethod( - TNode<Context> context, TNode<Object> receiver, const char* method_name, - IterationKind kind) { - Label throw_bad_receiver(this, Label::kDeferred); - - GotoIf(TaggedIsSmi(receiver), &throw_bad_receiver); - GotoIfNot(IsJSTypedArray(CAST(receiver)), &throw_bad_receiver); - - // Check if the {receiver}'s JSArrayBuffer was detached. - ThrowIfArrayBufferViewBufferIsDetached(context, CAST(receiver), method_name); - - Return(CreateArrayIterator(context, receiver, kind)); - - BIND(&throw_bad_receiver); - ThrowTypeError(context, MessageTemplate::kNotTypedArray, method_name); -} - -// ES #sec-%typedarray%.prototype.values -TF_BUILTIN(TypedArrayPrototypeValues, TypedArrayBuiltinsAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver)); - GenerateTypedArrayPrototypeIterationMethod(context, receiver, - "%TypedArray%.prototype.values()", - IterationKind::kValues); -} - -// ES #sec-%typedarray%.prototype.entries -TF_BUILTIN(TypedArrayPrototypeEntries, TypedArrayBuiltinsAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver)); - GenerateTypedArrayPrototypeIterationMethod(context, receiver, - "%TypedArray%.prototype.entries()", - IterationKind::kEntries); -} - -// ES #sec-%typedarray%.prototype.keys -TF_BUILTIN(TypedArrayPrototypeKeys, TypedArrayBuiltinsAssembler) { - TNode<Context> context = CAST(Parameter(Descriptor::kContext)); - TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver)); - GenerateTypedArrayPrototypeIterationMethod( - context, receiver, "%TypedArray%.prototype.keys()", IterationKind::kKeys); -} - } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/builtins/builtins-typed-array-gen.h b/chromium/v8/src/builtins/builtins-typed-array-gen.h index 1008b6bdd73..7b725ffc41f 100644 --- a/chromium/v8/src/builtins/builtins-typed-array-gen.h +++ b/chromium/v8/src/builtins/builtins-typed-array-gen.h @@ -16,11 +16,6 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler { explicit TypedArrayBuiltinsAssembler(compiler::CodeAssemblerState* state) : CodeStubAssembler(state) {} - void GenerateTypedArrayPrototypeIterationMethod(TNode<Context> context, - TNode<Object> receiver, - const char* method_name, - IterationKind iteration_kind); - void SetupTypedArrayEmbedderFields(TNode<JSTypedArray> holder); void AttachBuffer(TNode<JSTypedArray> holder, TNode<JSArrayBuffer> buffer, TNode<Map> map, TNode<Smi> length, diff --git a/chromium/v8/src/builtins/builtins-wasm-gen.cc b/chromium/v8/src/builtins/builtins-wasm-gen.cc index 28efa39c67d..1932db3ff40 100644 --- a/chromium/v8/src/builtins/builtins-wasm-gen.cc +++ b/chromium/v8/src/builtins/builtins-wasm-gen.cc @@ -37,12 +37,10 @@ TNode<FixedArray> WasmBuiltinsAssembler::LoadExternalFunctionsFromInstance( instance, WasmInstanceObject::kWasmExternalFunctionsOffset); } -TNode<Smi> WasmBuiltinsAssembler::SmiFromUint32WithSaturation( - TNode<Uint32T> value, uint32_t max) { - DCHECK_LE(max, static_cast<uint32_t>(Smi::kMaxValue)); - TNode<Uint32T> capped_value = SelectConstant( - Uint32LessThan(value, Uint32Constant(max)), value, Uint32Constant(max)); - return SmiFromUint32(capped_value); +TNode<FixedArray> WasmBuiltinsAssembler::LoadManagedObjectMapsFromInstance( + TNode<WasmInstanceObject> instance) { + return LoadObjectField<FixedArray>( + instance, WasmInstanceObject::kManagedObjectMapsOffset); } TF_BUILTIN(WasmFloat32ToNumber, WasmBuiltinsAssembler) { @@ -55,22 +53,6 @@ TF_BUILTIN(WasmFloat64ToNumber, WasmBuiltinsAssembler) { Return(ChangeFloat64ToTagged(val)); } -TF_BUILTIN(WasmAtomicNotify, WasmBuiltinsAssembler) { - TNode<Uint32T> address = - UncheckedCast<Uint32T>(Parameter(Descriptor::kAddress)); - TNode<Uint32T> count = UncheckedCast<Uint32T>(Parameter(Descriptor::kCount)); - - TNode<WasmInstanceObject> instance = LoadInstanceFromFrame(); - TNode<Number> address_number = ChangeUint32ToTagged(address); - TNode<Number> count_number = ChangeUint32ToTagged(count); - TNode<Context> context = LoadContextFromInstance(instance); - - TNode<Smi> result_smi = - CAST(CallRuntime(Runtime::kWasmAtomicNotify, context, instance, - address_number, count_number)); - Return(Unsigned(SmiToInt32(result_smi))); -} - TF_BUILTIN(WasmI32AtomicWait32, WasmBuiltinsAssembler) { if (!Is32()) { Unreachable(); @@ -100,33 +82,6 @@ TF_BUILTIN(WasmI32AtomicWait32, WasmBuiltinsAssembler) { Return(Unsigned(SmiToInt32(result_smi))); } -TF_BUILTIN(WasmI32AtomicWait64, WasmBuiltinsAssembler) { - if (!Is64()) { - Unreachable(); - return; - } - - TNode<Uint32T> address = - UncheckedCast<Uint32T>(Parameter(Descriptor::kAddress)); - TNode<Number> address_number = ChangeUint32ToTagged(address); - - TNode<Int32T> expected_value = - UncheckedCast<Int32T>(Parameter(Descriptor::kExpectedValue)); - TNode<Number> expected_value_number = ChangeInt32ToTagged(expected_value); - - TNode<IntPtrT> timeout_raw = - UncheckedCast<IntPtrT>(Parameter(Descriptor::kTimeout)); - TNode<BigInt> timeout = BigIntFromInt64(timeout_raw); - - TNode<WasmInstanceObject> instance = LoadInstanceFromFrame(); - TNode<Context> context = LoadContextFromInstance(instance); - - TNode<Smi> result_smi = - CAST(CallRuntime(Runtime::kWasmI32AtomicWait, context, instance, - address_number, expected_value_number, timeout)); - Return(Unsigned(SmiToInt32(result_smi))); -} - TF_BUILTIN(WasmI64AtomicWait32, WasmBuiltinsAssembler) { if (!Is32()) { Unreachable(); @@ -159,93 +114,6 @@ TF_BUILTIN(WasmI64AtomicWait32, WasmBuiltinsAssembler) { Return(Unsigned(SmiToInt32(result_smi))); } -TF_BUILTIN(WasmI64AtomicWait64, WasmBuiltinsAssembler) { - if (!Is64()) { - Unreachable(); - return; - } - - TNode<Uint32T> address = - UncheckedCast<Uint32T>(Parameter(Descriptor::kAddress)); - TNode<Number> address_number = ChangeUint32ToTagged(address); - - TNode<IntPtrT> expected_value_raw = - UncheckedCast<IntPtrT>(Parameter(Descriptor::kExpectedValue)); - TNode<BigInt> expected_value = BigIntFromInt64(expected_value_raw); - - TNode<IntPtrT> timeout_raw = - UncheckedCast<IntPtrT>(Parameter(Descriptor::kTimeout)); - TNode<BigInt> timeout = BigIntFromInt64(timeout_raw); - - TNode<WasmInstanceObject> instance = LoadInstanceFromFrame(); - TNode<Context> context = LoadContextFromInstance(instance); - - TNode<Smi> result_smi = - CAST(CallRuntime(Runtime::kWasmI64AtomicWait, context, instance, - address_number, expected_value, timeout)); - Return(Unsigned(SmiToInt32(result_smi))); -} - -TF_BUILTIN(WasmTableInit, WasmBuiltinsAssembler) { - TNode<Uint32T> dst_raw = - UncheckedCast<Uint32T>(Parameter(Descriptor::kDestination)); - // We cap {dst}, {src}, and {size} by {wasm::kV8MaxWasmTableSize + 1} to make - // sure that the values fit into a Smi. - STATIC_ASSERT(static_cast<size_t>(Smi::kMaxValue) >= - wasm::kV8MaxWasmTableSize + 1); - constexpr uint32_t kCap = - static_cast<uint32_t>(wasm::kV8MaxWasmTableSize + 1); - TNode<Smi> dst = SmiFromUint32WithSaturation(dst_raw, kCap); - TNode<Uint32T> src_raw = - UncheckedCast<Uint32T>(Parameter(Descriptor::kSource)); - TNode<Smi> src = SmiFromUint32WithSaturation(src_raw, kCap); - TNode<Uint32T> size_raw = - UncheckedCast<Uint32T>(Parameter(Descriptor::kSize)); - TNode<Smi> size = SmiFromUint32WithSaturation(size_raw, kCap); - TNode<Smi> table_index = - UncheckedCast<Smi>(Parameter(Descriptor::kTableIndex)); - TNode<Smi> segment_index = - UncheckedCast<Smi>(Parameter(Descriptor::kSegmentIndex)); - TNode<WasmInstanceObject> instance = LoadInstanceFromFrame(); - TNode<Context> context = LoadContextFromInstance(instance); - - TailCallRuntime(Runtime::kWasmTableInit, context, instance, table_index, - segment_index, dst, src, size); -} - -TF_BUILTIN(WasmTableCopy, WasmBuiltinsAssembler) { - // We cap {dst}, {src}, and {size} by {wasm::kV8MaxWasmTableSize + 1} to make - // sure that the values fit into a Smi. - STATIC_ASSERT(static_cast<size_t>(Smi::kMaxValue) >= - wasm::kV8MaxWasmTableSize + 1); - constexpr uint32_t kCap = - static_cast<uint32_t>(wasm::kV8MaxWasmTableSize + 1); - - TNode<Uint32T> dst_raw = - UncheckedCast<Uint32T>(Parameter(Descriptor::kDestination)); - TNode<Smi> dst = SmiFromUint32WithSaturation(dst_raw, kCap); - - TNode<Uint32T> src_raw = - UncheckedCast<Uint32T>(Parameter(Descriptor::kSource)); - TNode<Smi> src = SmiFromUint32WithSaturation(src_raw, kCap); - - TNode<Uint32T> size_raw = - UncheckedCast<Uint32T>(Parameter(Descriptor::kSize)); - TNode<Smi> size = SmiFromUint32WithSaturation(size_raw, kCap); - - TNode<Smi> dst_table = - UncheckedCast<Smi>(Parameter(Descriptor::kDestinationTable)); - - TNode<Smi> src_table = - UncheckedCast<Smi>(Parameter(Descriptor::kSourceTable)); - - TNode<WasmInstanceObject> instance = LoadInstanceFromFrame(); - TNode<Context> context = LoadContextFromInstance(instance); - - TailCallRuntime(Runtime::kWasmTableCopy, context, instance, dst_table, - src_table, dst, src, size); -} - TF_BUILTIN(WasmAllocateArray, WasmBuiltinsAssembler) { TNode<WasmInstanceObject> instance = LoadInstanceFromFrame(); TNode<Smi> map_index = CAST(Parameter(Descriptor::kMapIndex)); @@ -270,18 +138,5 @@ TF_BUILTIN(WasmAllocateArray, WasmBuiltinsAssembler) { Return(result); } -TF_BUILTIN(WasmAllocateStruct, WasmBuiltinsAssembler) { - TNode<WasmInstanceObject> instance = LoadInstanceFromFrame(); - TNode<Smi> map_index = CAST(Parameter(Descriptor::kMapIndex)); - TNode<FixedArray> maps_list = LoadObjectField<FixedArray>( - instance, WasmInstanceObject::kManagedObjectMapsOffset); - TNode<Map> map = CAST(LoadFixedArrayElement(maps_list, map_index)); - TNode<IntPtrT> instance_size = - TimesTaggedSize(LoadMapInstanceSizeInWords(map)); - TNode<WasmStruct> result = UncheckedCast<WasmStruct>(Allocate(instance_size)); - StoreMap(result, map); - Return(result); -} - } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/builtins/builtins-wasm-gen.h b/chromium/v8/src/builtins/builtins-wasm-gen.h index 3740560666d..ccf5bae7a15 100644 --- a/chromium/v8/src/builtins/builtins-wasm-gen.h +++ b/chromium/v8/src/builtins/builtins-wasm-gen.h @@ -25,8 +25,8 @@ class WasmBuiltinsAssembler : public CodeStubAssembler { TNode<FixedArray> LoadExternalFunctionsFromInstance( TNode<WasmInstanceObject> instance); - protected: - TNode<Smi> SmiFromUint32WithSaturation(TNode<Uint32T> value, uint32_t max); + TNode<FixedArray> LoadManagedObjectMapsFromInstance( + TNode<WasmInstanceObject> instance); }; } // namespace internal diff --git a/chromium/v8/src/builtins/cast.tq b/chromium/v8/src/builtins/cast.tq index dfac2035784..9adbd7ecc4f 100644 --- a/chromium/v8/src/builtins/cast.tq +++ b/chromium/v8/src/builtins/cast.tq @@ -2,56 +2,28 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -extern macro IsAllocationSite(HeapObject): bool; extern macro IsBigInt(HeapObject): bool; extern macro IsConstructor(HeapObject): bool; extern macro IsContext(HeapObject): bool; extern macro IsCustomElementsReceiverInstanceType(int32): bool; extern macro IsExtensibleMap(Map): bool; -extern macro IsFeedbackCell(HeapObject): bool; -extern macro IsFeedbackVector(HeapObject): bool; extern macro IsFixedArray(HeapObject): bool; extern macro IsHeapNumber(HeapObject): bool; -extern macro IsJSAggregateError(HeapObject): bool; -extern macro IsJSArray(HeapObject): bool; extern macro IsJSArrayMap(Map): bool; -extern macro IsJSBoundFunction(HeapObject): bool; -extern macro IsJSFinalizationRegistry(HeapObject): bool; -extern macro IsJSFunction(HeapObject): bool; -extern macro IsJSObject(HeapObject): bool; -extern macro IsJSPrimitiveWrapper(HeapObject): bool; -extern macro IsJSPromise(HeapObject): bool; extern macro IsJSProxy(HeapObject): bool; -extern macro IsJSReceiver(HeapObject): bool; -extern macro IsJSRegExp(HeapObject): bool; -extern macro IsJSRegExpStringIterator(HeapObject): bool; -extern macro IsJSTypedArray(HeapObject): bool; -extern macro IsMap(HeapObject): bool; extern macro IsName(HeapObject): bool; extern macro IsNativeContext(HeapObject): bool; -extern macro IsNumberDictionary(HeapObject): bool; extern macro IsNumberNormalized(Number): bool; extern macro IsNumber(Object): bool; -extern macro IsOddball(HeapObject): bool; extern macro IsPrivateSymbol(HeapObject): bool; -extern macro IsPromiseCapability(HeapObject): bool; -extern macro IsPromiseFulfillReactionJobTask(HeapObject): bool; -extern macro IsPromiseReaction(HeapObject): bool; -extern macro IsPromiseReactionJobTask(HeapObject): bool; -extern macro IsPromiseRejectReactionJobTask(HeapObject): bool; extern macro IsSafeInteger(Object): bool; -extern macro IsSharedFunctionInfo(HeapObject): bool; -extern macro IsSymbol(HeapObject): bool; -extern macro IsTuple2(HeapObject): bool; -extern macro HeapObjectToJSDataView(HeapObject): JSDataView - labels CastError; -extern macro HeapObjectToJSProxy(HeapObject): JSProxy - labels CastError; -extern macro HeapObjectToJSStringIterator(HeapObject): JSStringIterator - labels CastError; -extern macro HeapObjectToJSArrayBuffer(HeapObject): JSArrayBuffer - labels CastError; +@export +macro IsAllocationSite(o: HeapObject): bool { + Cast<AllocationSite>(o) otherwise return false; + return true; +} + extern macro TaggedToHeapObject(Object): HeapObject labels CastError; extern macro TaggedToSmi(Object): Smi @@ -60,28 +32,13 @@ extern macro TaggedToPositiveSmi(Object): PositiveSmi labels CastError; extern macro TaggedToDirectString(Object): DirectString labels CastError; -extern macro HeapObjectToJSAggregateError(HeapObject): JSAggregateError - labels CastError; -extern macro HeapObjectToJSArray(HeapObject): JSArray - labels CastError; extern macro HeapObjectToCallable(HeapObject): Callable labels CastError; -extern macro HeapObjectToFixedArray(HeapObject): FixedArray - labels CastError; -extern macro HeapObjectToFixedDoubleArray(HeapObject): FixedDoubleArray - labels CastError; -extern macro HeapObjectToString(HeapObject): String - labels CastError; extern macro HeapObjectToConstructor(HeapObject): Constructor labels CastError; extern macro HeapObjectToJSFunctionWithPrototypeSlot(HeapObject): JSFunctionWithPrototypeSlot labels CastError; -extern macro HeapObjectToHeapNumber(HeapObject): HeapNumber - labels CastError; -extern macro HeapObjectToSloppyArgumentsElements(HeapObject): - SloppyArgumentsElements - labels CastError; extern macro TaggedToNumber(Object): Number labels CastError; @@ -90,7 +47,17 @@ macro Cast<A : type extends WeakHeapObject>(o: A|Object): A labels CastError { return %RawDownCast<A>(o); } -macro Cast<A: type>(o: MaybeObject): A labels CastError; +macro Cast<A : type extends Object>(implicit context: Context)(o: MaybeObject): + A labels CastError { + typeswitch (o) { + case (WeakHeapObject): { + goto CastError; + } + case (o: Object): { + return Cast<A>(o) otherwise CastError; + } + } +} Cast<Undefined>(o: MaybeObject): Undefined labels CastError { if (TaggedNotEqual(o, Undefined)) goto CastError; @@ -283,22 +250,6 @@ Cast<Undefined>(o: HeapObject): Undefined return Cast<Undefined>(o) otherwise CastError; } -Cast<AllocationSite>(o: HeapObject): AllocationSite - labels CastError { - if (IsAllocationSite(o)) return %RawDownCast<AllocationSite>(o); - goto CastError; -} - -Cast<FixedArray>(o: HeapObject): FixedArray - labels CastError { - return HeapObjectToFixedArray(o) otherwise CastError; -} - -Cast<FixedDoubleArray>(o: HeapObject): FixedDoubleArray - labels CastError { - return HeapObjectToFixedDoubleArray(o) otherwise CastError; -} - Cast<EmptyFixedArray>(o: Object): EmptyFixedArray labels CastError { if (o != kEmptyFixedArray) goto CastError; @@ -325,46 +276,6 @@ Cast<(FixedDoubleArray | EmptyFixedArray)>(o: HeapObject): FixedDoubleArray| } } -Cast<SloppyArgumentsElements>(o: HeapObject): SloppyArgumentsElements - labels CastError { - return HeapObjectToSloppyArgumentsElements(o) otherwise CastError; -} - -Cast<JSDataView>(o: HeapObject): JSDataView - labels CastError { - return HeapObjectToJSDataView(o) otherwise CastError; -} - -Cast<JSProxy>(o: HeapObject): JSProxy - labels CastError { - return HeapObjectToJSProxy(o) otherwise CastError; -} - -Cast<JSStringIterator>(o: HeapObject): JSStringIterator - labels CastError { - return HeapObjectToJSStringIterator(o) otherwise CastError; -} - -Cast<JSRegExpStringIterator>(o: HeapObject): JSRegExpStringIterator - labels CastError { - if (IsJSRegExpStringIterator(o)) { - return %RawDownCast<JSRegExpStringIterator>(o); - } - goto CastError; -} - -Cast<JSTypedArray>(o: HeapObject): JSTypedArray - labels CastError { - if (IsJSTypedArray(o)) return %RawDownCast<JSTypedArray>(o); - goto CastError; -} - -Cast<JSTypedArray>(implicit context: Context)(o: Object): JSTypedArray - labels CastError { - const heapObject = Cast<HeapObject>(o) otherwise CastError; - return Cast<JSTypedArray>(heapObject) otherwise CastError; -} - Cast<Callable>(o: HeapObject): Callable labels CastError { return HeapObjectToCallable(o) otherwise CastError; @@ -376,62 +287,6 @@ Cast<Undefined|Callable>(o: HeapObject): Undefined|Callable return HeapObjectToCallable(o) otherwise CastError; } -Cast<JSAggregateError>(o: HeapObject): JSAggregateError - labels CastError { - return HeapObjectToJSAggregateError(o) otherwise CastError; -} - -Cast<JSArray>(o: HeapObject): JSArray - labels CastError { - return HeapObjectToJSArray(o) otherwise CastError; -} - -Cast<JSArrayBuffer>(o: HeapObject): JSArrayBuffer - labels CastError { - return HeapObjectToJSArrayBuffer(o) otherwise CastError; -} - -Cast<Context>(o: HeapObject): Context - labels CastError { - if (IsContext(o)) return %RawDownCast<Context>(o); - goto CastError; -} - -Cast<NativeContext>(o: HeapObject): NativeContext - labels CastError { - if (IsNativeContext(o)) return %RawDownCast<NativeContext>(o); - goto CastError; -} - -Cast<JSObject>(o: HeapObject): JSObject - labels CastError { - if (IsJSObject(o)) return %RawDownCast<JSObject>(o); - goto CastError; -} - -Cast<NumberDictionary>(o: HeapObject): NumberDictionary - labels CastError { - if (IsNumberDictionary(o)) return %RawDownCast<NumberDictionary>(o); - goto CastError; -} - -Cast<String>(o: HeapObject): String - labels CastError { - return HeapObjectToString(o) otherwise CastError; -} - -Cast<Oddball>(o: HeapObject): Oddball - labels CastError { - if (IsOddball(o)) return %RawDownCast<Oddball>(o); - goto CastError; -} - -Cast<Symbol>(o: HeapObject): Symbol - labels CastError { - if (IsSymbol(o)) return %RawDownCast<Symbol>(o); - goto CastError; -} - macro Cast<T : type extends Symbol>(o: Symbol): T labels CastError; Cast<PublicSymbol>(o: Symbol): PublicSymbol labels CastError { if (IsPrivateSymbol(o)) goto CastError; @@ -468,53 +323,17 @@ Cast<JSFunctionWithPrototypeSlot>(o: HeapObject): JSFunctionWithPrototypeSlot return HeapObjectToJSFunctionWithPrototypeSlot(o) otherwise CastError; } -Cast<HeapNumber>(o: HeapObject): HeapNumber - labels CastError { - if (IsHeapNumber(o)) return %RawDownCast<HeapNumber>(o); - goto CastError; -} - Cast<BigInt>(o: HeapObject): BigInt labels CastError { if (IsBigInt(o)) return %RawDownCast<BigInt>(o); goto CastError; } -Cast<JSRegExp>(o: HeapObject): JSRegExp - labels CastError { - if (IsJSRegExp(o)) return %RawDownCast<JSRegExp>(o); - goto CastError; -} - Cast<JSRegExpResult>(implicit context: Context)(o: HeapObject): JSRegExpResult labels CastError { if (regexp::IsRegExpResult(o)) return %RawDownCast<JSRegExpResult>(o); goto CastError; } -Cast<Map>(implicit context: Context)(o: HeapObject): Map - labels CastError { - if (IsMap(o)) return %RawDownCast<Map>(o); - goto CastError; -} - -Cast<FeedbackCell>(implicit context: Context)(o: HeapObject): FeedbackCell - labels CastError { - if (IsFeedbackCell(o)) return %RawDownCast<FeedbackCell>(o); - goto CastError; -} - -Cast<FeedbackVector>(implicit context: Context)(o: HeapObject): FeedbackVector - labels CastError { - if (IsFeedbackVector(o)) return %RawDownCast<FeedbackVector>(o); - goto CastError; -} - -Cast<JSPrimitiveWrapper>(o: HeapObject): JSPrimitiveWrapper - labels CastError { - if (IsJSPrimitiveWrapper(o)) return %RawDownCast<JSPrimitiveWrapper>(o); - goto CastError; -} - Cast<JSSloppyArgumentsObject>(implicit context: Context)(o: HeapObject): JSSloppyArgumentsObject labels CastError { @@ -623,32 +442,6 @@ Cast<FastJSArrayForReadWithNoCustomIteration>(implicit context: Context)( return %RawDownCast<FastJSArrayForReadWithNoCustomIteration>(a); } -Cast<JSReceiver>(o: HeapObject): JSReceiver - labels CastError { - if (IsJSReceiver(o)) return %RawDownCast<JSReceiver>(o); - goto CastError; -} - -Cast<JSFunction>(implicit context: Context)(o: HeapObject): JSFunction - labels CastError { - if (IsJSFunction(o)) return %RawDownCast<JSFunction>(o); - goto CastError; -} - -extern macro IsDebugInfo(HeapObject): bool; -Cast<DebugInfo>(implicit context: Context)(o: HeapObject): DebugInfo - labels CastError { - if (IsDebugInfo(o)) return %RawDownCast<DebugInfo>(o); - goto CastError; -} - -extern macro IsCoverageInfo(HeapObject): bool; -Cast<CoverageInfo>(implicit context: Context)(o: HeapObject): CoverageInfo - labels CastError { - if (IsCoverageInfo(o)) return %RawDownCast<CoverageInfo>(o); - goto CastError; -} - Cast<JSReceiver|Null>(o: HeapObject): JSReceiver|Null labels CastError { typeswitch (o) { @@ -664,35 +457,6 @@ Cast<JSReceiver|Null>(o: HeapObject): JSReceiver|Null } } -Cast<PromiseReactionJobTask>(o: HeapObject): - PromiseReactionJobTask labels CastError { - if (IsPromiseReactionJobTask(o)) { - return %RawDownCast<PromiseReactionJobTask>(o); - } - goto CastError; -} - -Cast<PromiseFulfillReactionJobTask>(o: HeapObject): - PromiseFulfillReactionJobTask labels CastError { - if (IsPromiseFulfillReactionJobTask(o)) { - return %RawDownCast<PromiseFulfillReactionJobTask>(o); - } - goto CastError; -} - -Cast<PromiseRejectReactionJobTask>(o: HeapObject): - PromiseRejectReactionJobTask labels CastError { - if (IsPromiseRejectReactionJobTask(o)) { - return %RawDownCast<PromiseRejectReactionJobTask>(o); - } - goto CastError; -} - -Cast<PromiseReaction>(o: HeapObject): PromiseReaction labels CastError { - if (IsPromiseReaction(o)) return %RawDownCast<PromiseReaction>(o); - goto CastError; -} - Cast<Smi|PromiseReaction>(o: Object): Smi|PromiseReaction labels CastError { typeswitch (o) { case (o: Smi): { @@ -737,32 +501,35 @@ Cast<Zero|PromiseReaction>(implicit context: Context)(o: Object): Zero| } } -Cast<JSBoundFunction>(o: HeapObject): JSBoundFunction labels CastError { - if (IsJSBoundFunction(o)) return %RawDownCast<JSBoundFunction>(o); - goto CastError; -} - -Cast<PromiseCapability>(o: HeapObject): PromiseCapability labels CastError { - if (IsPromiseCapability(o)) return %RawDownCast<PromiseCapability>(o); - goto CastError; +Cast<JSFunction|JSBoundFunction>(implicit context: Context)(o: Object): + JSFunction|JSBoundFunction labels CastError { + typeswitch (o) { + case (o: JSFunction): { + return o; + } + case (o: JSBoundFunction): { + return o; + } + case (Object): { + goto CastError; + } + } } -Cast<SharedFunctionInfo>(o: HeapObject): SharedFunctionInfo labels CastError { - if (IsSharedFunctionInfo(o)) return %RawDownCast<SharedFunctionInfo>(o); - goto CastError; +macro Is<A : type extends Object, B : type extends Object>( + implicit context: Context)(o: B): bool { + Cast<A>(o) otherwise return false; + return true; } -Cast<JSPromise>(o: HeapObject): JSPromise labels CastError { - if (IsJSPromise(o)) return %RawDownCast<JSPromise>(o); - goto CastError; +macro UnsafeCast<A : type extends Object>(implicit context: Context)(o: Object): + A { + assert(Is<A>(o)); + return %RawDownCast<A>(o); } -Cast<JSFinalizationRegistry>(o: HeapObject): - JSFinalizationRegistry labels CastError { - if (IsJSFinalizationRegistry(o)) { - return %RawDownCast<JSFinalizationRegistry>(o); - } - goto CastError; +macro UnsafeConstCast<T: type>(r: const &T):&T { + return %RawDownCast<&T>(r); } UnsafeCast<RegExpMatchInfo>(implicit context: Context)(o: Object): diff --git a/chromium/v8/src/builtins/constants-table-builder.cc b/chromium/v8/src/builtins/constants-table-builder.cc index 94e8dc05ec7..fa333726e79 100644 --- a/chromium/v8/src/builtins/constants-table-builder.cc +++ b/chromium/v8/src/builtins/constants-table-builder.cc @@ -57,24 +57,30 @@ uint32_t BuiltinsConstantsTableBuilder::AddObject(Handle<Object> object) { } } -void BuiltinsConstantsTableBuilder::PatchSelfReference( - Handle<Object> self_reference, Handle<Code> code_object) { -#ifdef DEBUG +namespace { +void CheckPreconditionsForPatching(Isolate* isolate, + Handle<Object> replacement_object) { // Roots must not be inserted into the constants table as they are already - // accessibly from the root list. + // accessible from the root list. RootIndex root_list_index; - DCHECK(!isolate_->roots_table().IsRootHandle(code_object, &root_list_index)); + DCHECK(!isolate->roots_table().IsRootHandle(replacement_object, + &root_list_index)); + USE(root_list_index); // Not yet finalized. - DCHECK_EQ(ReadOnlyRoots(isolate_).empty_fixed_array(), - isolate_->heap()->builtins_constants_table()); + DCHECK_EQ(ReadOnlyRoots(isolate).empty_fixed_array(), + isolate->heap()->builtins_constants_table()); - DCHECK(isolate_->IsGeneratingEmbeddedBuiltins()); + DCHECK(isolate->IsGeneratingEmbeddedBuiltins()); +} +} // namespace +void BuiltinsConstantsTableBuilder::PatchSelfReference( + Handle<Object> self_reference, Handle<Code> code_object) { + CheckPreconditionsForPatching(isolate_, code_object); DCHECK(self_reference->IsOddball()); DCHECK(Oddball::cast(*self_reference).kind() == Oddball::kSelfReferenceMarker); -#endif uint32_t key; if (map_.Delete(self_reference, &key)) { @@ -83,6 +89,17 @@ void BuiltinsConstantsTableBuilder::PatchSelfReference( } } +void BuiltinsConstantsTableBuilder::PatchBasicBlockCountersReference( + Handle<ByteArray> counters) { + CheckPreconditionsForPatching(isolate_, counters); + + uint32_t key; + if (map_.Delete(ReadOnlyRoots(isolate_).basic_block_counters_marker(), + &key)) { + map_.Set(counters, key); + } +} + void BuiltinsConstantsTableBuilder::Finalize() { HandleScope handle_scope(isolate_); @@ -117,6 +134,8 @@ void BuiltinsConstantsTableBuilder::Finalize() { DCHECK(table->get(i).IsHeapObject()); DCHECK_NE(ReadOnlyRoots(isolate_).undefined_value(), table->get(i)); DCHECK_NE(ReadOnlyRoots(isolate_).self_reference_marker(), table->get(i)); + DCHECK_NE(ReadOnlyRoots(isolate_).basic_block_counters_marker(), + table->get(i)); } #endif diff --git a/chromium/v8/src/builtins/constants-table-builder.h b/chromium/v8/src/builtins/constants-table-builder.h index 89c95912a1e..fa9d7dee3a3 100644 --- a/chromium/v8/src/builtins/constants-table-builder.h +++ b/chromium/v8/src/builtins/constants-table-builder.h @@ -34,6 +34,11 @@ class BuiltinsConstantsTableBuilder final { void PatchSelfReference(Handle<Object> self_reference, Handle<Code> code_object); + // References to the array that stores basic block usage counters start out as + // references to a unique oddball. Once the actual array has been allocated, + // such entries in the constants map must be patched up. + void PatchBasicBlockCountersReference(Handle<ByteArray> counters); + // Should be called after all affected code (e.g. builtins and bytecode // handlers) has been generated. void Finalize(); diff --git a/chromium/v8/src/builtins/conversion.tq b/chromium/v8/src/builtins/conversion.tq new file mode 100644 index 00000000000..7f634d94905 --- /dev/null +++ b/chromium/v8/src/builtins/conversion.tq @@ -0,0 +1,232 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +namespace runtime { +extern transitioning runtime ToStringRT(Context, BigInt): String; +} + +extern enum OrdinaryToPrimitiveHint { kString, kNumber } + +extern macro OrdinaryToPrimitive(implicit context: Context)( + JSAny, constexpr OrdinaryToPrimitiveHint): JSPrimitive; + +namespace conversion { + +builtin StringToNumber(implicit context: Context)(input: String): Number { + return ::StringToNumber(input); +} + +transitioning builtin NonNumberToNumber(implicit context: Context)( + input: JSAnyNotNumber): Number { + return ::NonNumberToNumber(input); +} + +transitioning builtin NonNumberToNumeric(implicit context: Context)( + input: JSAnyNotNumber): Numeric { + return ::NonNumberToNumeric(input); +} + +transitioning builtin ToNumeric(implicit context: Context)(input: JSAny): + Numeric { + typeswitch (input) { + case (n: Number): { + return n; + } + case (h: JSAnyNotNumber): { + return conversion::NonNumberToNumeric(h); + } + } +} + +// ES section #sec-tostring-applied-to-the-number-type +builtin NumberToString(implicit context: Context)(input: Number): String { + return ::NumberToString(input); +} + +// ES6 section 7.1.2 ToBoolean ( argument ) +builtin ToBoolean(implicit context: Context)(input: JSAny): Boolean { + BranchIfToBooleanIsTrue(input) otherwise return TrueConstant(), + return FalseConstant(); +} + +transitioning builtin ToLength(implicit context: Context)(input: JSAny): + Number { + // We might need to loop once for ToNumber conversion. + let x: JSAny = input; + while (true) { + typeswitch (x) { + case (s: Smi): { + if (s < 0) return 0; + return s; + } + case (h: HeapNumber): { + let value: float64 = Convert<float64>(h); + // The sense of this test is important for the NaN and -0 cases. + if (!(value > 0)) return 0; + if (value > kMaxSafeInteger) return kMaxSafeInteger; + value = math::Float64Floor(value); + return ChangeFloat64ToTagged(value); + } + case (h: JSAnyNotNumber): { + x = ::NonNumberToNumber(h); + } + } + } + VerifiedUnreachable(); +} + +transitioning builtin ToName(implicit context: Context)(input: JSAny): Name { + // We might need to loop once for ToNumber conversion. + let x: JSAny = input; + while (true) { + typeswitch (x) { + case (n: Name): { + return n; + } + case (n: Number): { + return ::NumberToString(n); + } + case (b: BigInt): { + // We don't have a fast-path for BigInt currently, so just + // tail call to the %ToString runtime function here for now. + tail runtime::ToStringRT(context, b); + } + case (o: Oddball): { + return o.to_string; + } + case (o: JSReceiver): { + x = NonPrimitiveToPrimitive_String(o); + } + } + } + VerifiedUnreachable(); +} + +const kNoConstructorFunctionIndex: + constexpr int31 generates 'Map::kNoConstructorFunctionIndex'; + +// ES6 section 7.1.13 ToObject (argument) +transitioning builtin ToObject(implicit context: Context)(input: JSAny): + JSReceiver { + try { + typeswitch (input) { + case (Smi): { + goto WrapPrimitive(NativeContextSlot::NUMBER_FUNCTION_INDEX); + } + case (o: JSReceiver): { + return o; + } + case (o: JSAnyNotSmi): { + const index: intptr = Convert<intptr>( + o.map.in_object_properties_start_or_constructor_function_index); + if (index != kNoConstructorFunctionIndex) goto WrapPrimitive(index); + ThrowTypeError(MessageTemplate::kUndefinedOrNullToObject, 'ToObject'); + } + } + } label WrapPrimitive(constructorIndex: intptr) { + const nativeContext = LoadNativeContext(context); + const constructor = UnsafeCast<JSFunction>(nativeContext[constructorIndex]); + const map: Map = UnsafeCast<Map>(constructor.prototype_or_initial_map); + const wrapper = + UnsafeCast<JSPrimitiveWrapper>(AllocateFastOrSlowJSObjectFromMap(map)); + wrapper.value = input; + return wrapper; + } +} + +// ES6 section 7.1.1 ToPrimitive ( input [ , PreferredType ] ) + +transitioning macro TryGetExoticToPrimitive(implicit context: Context)( + input: JSAny): JSAny labels OrdinaryToPrimitive { + // Look up the @@toPrimitive property. + const exoticToPrimitive: JSAny = + GetProperty(input, ToPrimitiveSymbolConstant()); + if (IsNullOrUndefined(exoticToPrimitive)) goto OrdinaryToPrimitive; + return exoticToPrimitive; +} + +transitioning macro CallExoticToPrimitive(implicit context: Context)( + input: JSAny, exoticToPrimitive: JSAny, hint: String): JSPrimitive { + // Invoke the exoticToPrimitive method on the input with a string + // representation of the hint. + const result: JSAny = Call(context, exoticToPrimitive, input, hint); + + // Verify that the result is primitive. + typeswitch (result) { + case (o: JSPrimitive): { + return o; + } + case (JSReceiver): { + // Somehow the @@toPrimitive method on input didn't yield a primitive. + ThrowTypeError(MessageTemplate::kCannotConvertToPrimitive); + } + } +} + +transitioning builtin NonPrimitiveToPrimitive_Default( + implicit context: Context)(input: JSReceiver): JSPrimitive { + const exoticToPrimitive: JSAny = TryGetExoticToPrimitive(input) + otherwise return OrdinaryToPrimitive_Number(input); + return CallExoticToPrimitive( + input, exoticToPrimitive, DefaultStringConstant()); +} + +transitioning builtin NonPrimitiveToPrimitive_Number(implicit context: Context)( + input: JSReceiver): JSPrimitive { + const exoticToPrimitive: JSAny = TryGetExoticToPrimitive(input) + otherwise return OrdinaryToPrimitive_Number(input); + return CallExoticToPrimitive( + input, exoticToPrimitive, NumberStringConstant()); +} + +transitioning builtin NonPrimitiveToPrimitive_String(implicit context: Context)( + input: JSReceiver): JSPrimitive { + const exoticToPrimitive: JSAny = TryGetExoticToPrimitive(input) + otherwise return OrdinaryToPrimitive_String(input); + return CallExoticToPrimitive( + input, exoticToPrimitive, StringStringConstant()); +} + +// 7.1.1.1 OrdinaryToPrimitive ( O, hint ) + +transitioning macro TryToPrimitiveMethod(implicit context: Context)( + input: JSAny, name: String): JSPrimitive labels Continue { + const method: JSAny = GetProperty(input, name); + typeswitch (method) { + case (Callable): { + const value: JSAny = Call(context, method, input); + return Cast<JSPrimitive>(value) otherwise Continue; + } + case (JSAny): { + goto Continue; + } + } +} + +transitioning builtin OrdinaryToPrimitive_Number(implicit context: Context)( + input: JSAny): JSPrimitive { + try { + return TryToPrimitiveMethod(input, ValueOfStringConstant()) + otherwise String; + } label String { + return TryToPrimitiveMethod(input, ToStringStringConstant()) + otherwise Throw; + } label Throw { + ThrowTypeError(MessageTemplate::kCannotConvertToPrimitive); + } +} + +transitioning builtin OrdinaryToPrimitive_String(implicit context: Context)( + input: JSAny): JSPrimitive { + try { + return TryToPrimitiveMethod(input, ToStringStringConstant()) + otherwise String; + } label String { + return TryToPrimitiveMethod(input, ValueOfStringConstant()) otherwise Throw; + } label Throw { + ThrowTypeError(MessageTemplate::kCannotConvertToPrimitive); + } +} + +} // namespace conversion diff --git a/chromium/v8/src/builtins/convert.tq b/chromium/v8/src/builtins/convert.tq index e2c11120381..03440a183ad 100644 --- a/chromium/v8/src/builtins/convert.tq +++ b/chromium/v8/src/builtins/convert.tq @@ -94,6 +94,15 @@ FromConstexpr<PromiseState, constexpr PromiseState>(c: constexpr PromiseState): PromiseState { return %RawDownCast<PromiseState>(Int32Constant(c)); } +FromConstexpr<InstanceType, constexpr InstanceType>(c: constexpr InstanceType): + InstanceType { + return %RawDownCast<InstanceType>(Uint16Constant(c)); +} + +FromConstexpr<IterationKind, constexpr IterationKind>( + c: constexpr IterationKind): IterationKind { + return %RawDownCast<IterationKind>(Unsigned(%FromConstexpr<int32>(c))); +} macro Convert<To: type, From: type>(i: From): To { return i; @@ -103,6 +112,9 @@ macro Convert<To: type, From: type>(i: From): To labels Overflow { return i; } +Convert<Boolean, bool>(b: bool): Boolean { + return b ? True : False; +} extern macro ConvertElementsKindToInt(ElementsKind): int32; Convert<int32, ElementsKind>(elementsKind: ElementsKind): int32 { return ConvertElementsKindToInt(elementsKind); @@ -201,6 +213,9 @@ Convert<PositiveSmi, intptr>(i: intptr): PositiveSmi labels IfOverflow { goto IfOverflow; } } +Convert<PositiveSmi, uint32>(ui: uint32): PositiveSmi labels IfOverflow { + return Convert<PositiveSmi>(Convert<uintptr>(ui)) otherwise IfOverflow; +} Convert<int32, Smi>(s: Smi): int32 { return SmiToInt32(s); } diff --git a/chromium/v8/src/builtins/function.tq b/chromium/v8/src/builtins/function.tq new file mode 100644 index 00000000000..8266714c7be --- /dev/null +++ b/chromium/v8/src/builtins/function.tq @@ -0,0 +1,109 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +namespace function { + +extern macro OrdinaryHasInstance(Context, Object, Object): JSAny; + +// ES6 section 19.2.3.6 Function.prototype[@@hasInstance] +javascript builtin FunctionPrototypeHasInstance( + js-implicit context: NativeContext, receiver: JSAny)(value: JSAny): JSAny { + return OrdinaryHasInstance(context, receiver, value); +} + +extern transitioning builtin +FunctionPrototypeBind(implicit context: Context)( + JSFunction, JSAny, int32): JSAny; + +const kLengthDescriptorIndex: + constexpr int32 generates 'JSFunction::kLengthDescriptorIndex'; +const kNameDescriptorIndex: + constexpr int32 generates 'JSFunction::kNameDescriptorIndex'; +const kMinDescriptorsForFastBind: + constexpr int31 generates 'JSFunction::kMinDescriptorsForFastBind'; + +macro CheckAccessor(implicit context: Context)( + array: DescriptorArray, index: constexpr int32, name: Name) labels Slow { + const descriptor: DescriptorEntry = array.descriptors[index]; + const key: Name|Undefined = descriptor.key; + if (!TaggedEqual(key, name)) goto Slow; + + // The descriptor value must be an AccessorInfo. + Cast<AccessorInfo>(descriptor.value) otherwise goto Slow; +} + +// ES6 section 19.2.3.2 Function.prototype.bind +transitioning javascript builtin +FastFunctionPrototypeBind( + js-implicit context: NativeContext, receiver: JSAny, newTarget: JSAny, + target: JSFunction)(...arguments): JSAny { + const argc: intptr = arguments.length; + try { + typeswitch (receiver) { + case (fn: JSFunction|JSBoundFunction): { + // Disallow binding of slow-mode functions. We need to figure out + // whether the length and name property are in the original state. + Comment('Disallow binding of slow-mode functions'); + if (IsDictionaryMap(fn.map)) goto Slow; + + // Check whether the length and name properties are still present as + // AccessorInfo objects. If so, their value can be recomputed even if + // the actual value on the object changes. + + if (fn.map.bit_field3.number_of_own_descriptors < + kMinDescriptorsForFastBind) { + goto Slow; + } + + const descriptors: DescriptorArray = fn.map.instance_descriptors; + CheckAccessor( + descriptors, kLengthDescriptorIndex, LengthStringConstant()) + otherwise Slow; + CheckAccessor(descriptors, kNameDescriptorIndex, NameStringConstant()) + otherwise Slow; + + // Choose the right bound function map based on whether the target is + // constructable. + + const boundFunctionMap: Map = UnsafeCast<Map>( + IsConstructor(fn) ? + context[NativeContextSlot:: + BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX] : + context[NativeContextSlot:: + BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX]); + + // Verify that prototype matches that of the target bound function. + + if (fn.map.prototype != boundFunctionMap.prototype) goto Slow; + + // Allocate the arguments array. + + const argumentsArray = arguments.length <= 1 ? + kEmptyFixedArray : + NewFixedArray( + arguments.length - 1, ArgumentsIterator{arguments, current: 1}); + + const boundReceiver: JSAny = arguments[0]; + + const result = new JSBoundFunction{ + map: boundFunctionMap, + properties_or_hash: kEmptyFixedArray, + elements: kEmptyFixedArray, + bound_target_function: fn, + bound_this: boundReceiver, + bound_arguments: argumentsArray + }; + return result; + } + + case (JSAny): { + goto Slow; + } + } + } label Slow { + tail FunctionPrototypeBind( + LoadTargetFromFrame(), newTarget, Convert<int32>(argc)); + } +} +} // namespace function diff --git a/chromium/v8/src/builtins/growable-fixed-array.tq b/chromium/v8/src/builtins/growable-fixed-array.tq index 094e051a65a..af9418b0c91 100644 --- a/chromium/v8/src/builtins/growable-fixed-array.tq +++ b/chromium/v8/src/builtins/growable-fixed-array.tq @@ -25,9 +25,6 @@ struct GrowableFixedArray { this.array = this.ResizeFixedArray(this.capacity); } } - macro ToFixedArray(): FixedArray { - return this.ResizeFixedArray(this.length); - } macro ToJSArray(implicit context: Context)(): JSArray { const nativeContext: NativeContext = LoadNativeContext(context); diff --git a/chromium/v8/src/builtins/internal.tq b/chromium/v8/src/builtins/internal.tq new file mode 100644 index 00000000000..9e7e4240ba2 --- /dev/null +++ b/chromium/v8/src/builtins/internal.tq @@ -0,0 +1,35 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +namespace internal { + +namespace runtime { +extern runtime GetTemplateObject(implicit context: Context)( + TemplateObjectDescription, SharedFunctionInfo, Smi): JSAny; +} + +builtin GetTemplateObject( + context: Context, shared: SharedFunctionInfo, + description: TemplateObjectDescription, slot: uintptr, + maybeFeedbackVector: FeedbackVector|Undefined): JSArray { + // TODO(jgruber): Consider merging with the GetTemplateObject bytecode + // handler; the current advantage of the split implementation is that the + // bytecode can skip most work if feedback exists. + + try { + const vector = + Cast<FeedbackVector>(maybeFeedbackVector) otherwise CallRuntime; + return Cast<JSArray>(ic::LoadFeedbackVectorSlot(vector, slot)) + otherwise CallRuntime; + } label CallRuntime deferred { + const result = UnsafeCast<JSArray>(runtime::GetTemplateObject( + description, shared, Convert<Smi>(Signed(slot)))); + const vector = + Cast<FeedbackVector>(maybeFeedbackVector) otherwise return result; + ic::StoreFeedbackVectorSlot(vector, slot, result); + return result; + } +} + +} // namespace internal diff --git a/chromium/v8/src/builtins/math.tq b/chromium/v8/src/builtins/math.tq index 0586f432f5b..50bd3e2201b 100644 --- a/chromium/v8/src/builtins/math.tq +++ b/chromium/v8/src/builtins/math.tq @@ -4,9 +4,6 @@ namespace math { -extern transitioning builtin -NonNumberToNumber(implicit context: Context)(HeapObject): Number; - transitioning macro ReduceToSmiOrFloat64(implicit context: Context)(x: JSAny): never labels SmiResult(Smi), Float64Result(float64) { @@ -20,7 +17,7 @@ transitioning macro ReduceToSmiOrFloat64(implicit context: Context)(x: JSAny): goto Float64Result(Convert<float64>(h)); } case (a: JSAnyNotNumber): { - x1 = NonNumberToNumber(a); + x1 = conversion::NonNumberToNumber(a); } } } @@ -29,6 +26,7 @@ transitioning macro ReduceToSmiOrFloat64(implicit context: Context)(x: JSAny): // ES6 #sec-math.abs extern macro IsIntPtrAbsWithOverflowSupported(): constexpr bool; +extern macro TrySmiAdd(Smi, Smi): Smi labels Overflow; extern macro TrySmiSub(Smi, Smi): Smi labels Overflow; extern macro TrySmiAbs(Smi): Smi labels Overflow; extern macro Float64Abs(float64): float64; diff --git a/chromium/v8/src/builtins/number.tq b/chromium/v8/src/builtins/number.tq index 98680cf5533..753998424fa 100644 --- a/chromium/v8/src/builtins/number.tq +++ b/chromium/v8/src/builtins/number.tq @@ -2,9 +2,48 @@ // source code is governed by a BSD-style license that can be found in the // LICENSE file. +#include 'src/ic/binary-op-assembler.h' + +extern enum Operation extends uint31 { + // Binary operations. + kAdd, + kSubtract, + kMultiply, + kDivide, + kModulus, + kExponentiate, + kBitwiseAnd, + kBitwiseOr, + kBitwiseXor, + kShiftLeft, + kShiftRight, + kShiftRightLogical, + // Unary operations. + kBitwiseNot, + kNegate, + kIncrement, + kDecrement, + // Compare operations. + kEqual, + kStrictEqual, + kLessThan, + kLessThanOrEqual, + kGreaterThan, + kGreaterThanOrEqual +} + namespace runtime { extern transitioning runtime DoubleToStringWithRadix(implicit context: Context)(Number, Number): String; + +extern transitioning runtime StringParseFloat(implicit context: Context)( + String): Number; +extern transitioning runtime StringParseInt(implicit context: Context)( + JSAny, JSAny): Number; + +extern runtime BigIntUnaryOp(Context, BigInt, SmiTagged<Operation>): BigInt; +extern runtime BigIntBinaryOp( + Context, Numeric, Numeric, SmiTagged<Operation>): BigInt; } // namespace runtime namespace number { @@ -60,14 +99,649 @@ transitioning javascript builtin NumberPrototypeToString( if (x == -0) { return ZeroStringConstant(); - } else if (NumberIsNaN(x)) { + } else if (::NumberIsNaN(x)) { return NaNStringConstant(); } else if (x == V8_INFINITY) { return InfinityStringConstant(); } else if (x == MINUS_V8_INFINITY) { return MinusInfinityStringConstant(); } - return runtime::DoubleToStringWithRadix(x, radixNumber); } + +// ES6 #sec-number.isfinite +javascript builtin NumberIsFinite( + js-implicit context: NativeContext, + receiver: JSAny)(value: JSAny): Boolean { + typeswitch (value) { + case (Smi): { + return True; + } + case (h: HeapNumber): { + const number: float64 = Convert<float64>(h); + const infiniteOrNaN: bool = Float64IsNaN(number - number); + return Convert<Boolean>(!infiniteOrNaN); + } + case (JSAnyNotNumber): { + return False; + } + } +} + +// ES6 #sec-number.isinteger +javascript builtin NumberIsInteger(js-implicit context: NativeContext)( + value: JSAny): Boolean { + return SelectBooleanConstant(IsInteger(value)); +} + +// ES6 #sec-number.isnan +javascript builtin NumberIsNaN(js-implicit context: NativeContext)( + value: JSAny): Boolean { + typeswitch (value) { + case (Smi): { + return False; + } + case (h: HeapNumber): { + const number: float64 = Convert<float64>(h); + return Convert<Boolean>(Float64IsNaN(number)); + } + case (JSAnyNotNumber): { + return False; + } + } +} + +// ES6 #sec-number.issafeinteger +javascript builtin NumberIsSafeInteger(js-implicit context: NativeContext)( + value: JSAny): Boolean { + return SelectBooleanConstant(IsSafeInteger(value)); +} + +// ES6 #sec-number.prototype.valueof +transitioning javascript builtin NumberPrototypeValueOf( + js-implicit context: NativeContext, receiver: JSAny)(): JSAny { + return ToThisValue( + receiver, PrimitiveType::kNumber, 'Number.prototype.valueOf'); +} + +// ES6 #sec-number.parsefloat +transitioning javascript builtin NumberParseFloat( + js-implicit context: NativeContext)(value: JSAny): Number { + try { + typeswitch (value) { + case (s: Smi): { + return s; + } + case (h: HeapNumber): { + // The input is already a Number. Take care of -0. + // The sense of comparison is important for the NaN case. + return (Convert<float64>(h) == 0) ? SmiConstant(0) : h; + } + case (s: String): { + goto String(s); + } + case (HeapObject): { + goto String(string::ToString(context, value)); + } + } + } label String(s: String) { + // Check if the string is a cached array index. + const hash: NameHash = s.hash_field; + if (!hash.is_not_integer_index_mask && + hash.array_index_length < kMaxCachedArrayIndexLength) { + const arrayIndex: uint32 = hash.array_index_value; + return SmiFromUint32(arrayIndex); + } + // Fall back to the runtime to convert string to a number. + return runtime::StringParseFloat(s); + } +} + +extern macro TruncateFloat64ToWord32(float64): uint32; + +transitioning builtin ParseInt(implicit context: Context)( + input: JSAny, radix: JSAny): Number { + try { + // Check if radix should be 10 (i.e. undefined, 0 or 10). + if (radix != Undefined && !TaggedEqual(radix, SmiConstant(10)) && + !TaggedEqual(radix, SmiConstant(0))) { + goto CallRuntime; + } + + typeswitch (input) { + case (s: Smi): { + return s; + } + case (h: HeapNumber): { + // Check if the input value is in Signed32 range. + const asFloat64: float64 = Convert<float64>(h); + const asInt32: int32 = Signed(TruncateFloat64ToWord32(asFloat64)); + // The sense of comparison is important for the NaN case. + if (asFloat64 == ChangeInt32ToFloat64(asInt32)) goto Int32(asInt32); + + // Check if the absolute value of input is in the [1,1<<31[ range. Call + // the runtime for the range [0,1[ because the result could be -0. + const kMaxAbsValue: float64 = 2147483648.0; + const absInput: float64 = math::Float64Abs(asFloat64); + if (absInput < kMaxAbsValue && absInput >= 1) goto Int32(asInt32); + goto CallRuntime; + } + case (s: String): { + goto String(s); + } + case (HeapObject): { + goto CallRuntime; + } + } + } label Int32(i: int32) { + return ChangeInt32ToTagged(i); + } label String(s: String) { + // Check if the string is a cached array index. + const hash: NameHash = s.hash_field; + if (!hash.is_not_integer_index_mask && + hash.array_index_length < kMaxCachedArrayIndexLength) { + const arrayIndex: uint32 = hash.array_index_value; + return SmiFromUint32(arrayIndex); + } + // Fall back to the runtime. + goto CallRuntime; + } label CallRuntime { + tail runtime::StringParseInt(input, radix); + } +} + +// ES6 #sec-number.parseint +transitioning javascript builtin NumberParseInt( + js-implicit context: NativeContext)(value: JSAny, radix: JSAny): Number { + return ParseInt(value, radix); +} + +extern builtin NonNumberToNumeric(implicit context: Context)(JSAny): Numeric; +extern builtin BitwiseXor(implicit context: Context)(Number, Number): Number; +extern builtin Subtract(implicit context: Context)(Number, Number): Number; +extern builtin Add(implicit context: Context)(Number, Number): Number; +extern builtin StringAddConvertLeft(implicit context: Context)( + JSAny, String): JSAny; +extern builtin StringAddConvertRight(implicit context: Context)( + String, JSAny): JSAny; + +extern macro BitwiseOp(int32, int32, constexpr Operation): Number; +extern macro RelationalComparison( + constexpr Operation, JSAny, JSAny, Context): Boolean; + +// TODO(bbudge) Use a simpler macro structure that doesn't loop when converting +// non-numbers, if such a code sequence doesn't make the builtin bigger. + +transitioning macro ToNumericOrPrimitive(implicit context: Context)( + value: JSAny): JSAny { + typeswitch (value) { + case (v: JSReceiver): { + return NonPrimitiveToPrimitive_Default(context, v); + } + case (v: JSPrimitive): { + return NonNumberToNumeric(v); + } + } +} + +transitioning builtin Add(implicit context: Context)( + leftArg: JSAny, rightArg: JSAny): JSAny { + let left: JSAny = leftArg; + let right: JSAny = rightArg; + try { + while (true) { + typeswitch (left) { + case (left: Smi): { + typeswitch (right) { + case (right: Smi): { + return math::TrySmiAdd(left, right) otherwise goto Float64s( + SmiToFloat64(left), SmiToFloat64(right)); + } + case (right: HeapNumber): { + goto Float64s(SmiToFloat64(left), Convert<float64>(right)); + } + case (right: BigInt): { + goto Numerics(left, right); + } + case (right: String): { + goto StringAddConvertLeft(left, right); + } + case (HeapObject): { + right = ToNumericOrPrimitive(right); + continue; + } + } + } + case (left: HeapNumber): { + typeswitch (right) { + case (right: Smi): { + goto Float64s(Convert<float64>(left), SmiToFloat64(right)); + } + case (right: HeapNumber): { + goto Float64s(Convert<float64>(left), Convert<float64>(right)); + } + case (right: BigInt): { + goto Numerics(left, right); + } + case (right: String): { + goto StringAddConvertLeft(left, right); + } + case (HeapObject): { + right = ToNumericOrPrimitive(right); + continue; + } + } + } + case (left: BigInt): { + typeswitch (right) { + case (right: Numeric): { + goto Numerics(left, right); + } + case (right: String): { + goto StringAddConvertLeft(left, right); + } + case (HeapObject): { + right = ToNumericOrPrimitive(right); + continue; + } + } + } + case (left: String): { + goto StringAddConvertRight(left, right); + } + case (leftReceiver: JSReceiver): { + left = ToPrimitiveDefault(leftReceiver); + } + case (HeapObject): { + // left: HeapObject + typeswitch (right) { + case (right: String): { + goto StringAddConvertLeft(left, right); + } + case (rightReceiver: JSReceiver): { + // left is JSPrimitive and right is JSReceiver, convert right + // with priority. + right = ToPrimitiveDefault(rightReceiver); + continue; + } + case (JSPrimitive): { + // Neither left or right is JSReceiver, convert left. + left = NonNumberToNumeric(left); + continue; + } + } + } + } + } + } label StringAddConvertLeft(left: JSAny, right: String) { + tail StringAddConvertLeft(left, right); + } label StringAddConvertRight(left: String, right: JSAny) { + tail StringAddConvertRight(left, right); + } label Numerics(left: Numeric, right: Numeric) { + tail bigint::BigIntAdd(left, right); + } label Float64s(left: float64, right: float64) { + return AllocateHeapNumberWithValue(left + right); + } + unreachable; +} + +// Unary type switch on Number | BigInt. +macro UnaryOp1(implicit context: Context)(value: JSAny): never labels +Number(Number), BigInt(BigInt) { + let x: JSAny = value; + while (true) { + typeswitch (x) { + case (n: Number): { + goto Number(n); + } + case (b: BigInt): { + goto BigInt(b); + } + case (JSAnyNotNumeric): { + x = NonNumberToNumeric(x); + } + } + } + unreachable; +} + +// Unary type switch on Smi | HeapNumber | BigInt. +macro UnaryOp2(implicit context: Context)(value: JSAny): never labels +Smi(Smi), HeapNumber(HeapNumber), BigInt(BigInt) { + let x: JSAny = value; + while (true) { + typeswitch (x) { + case (s: Smi): { + goto Smi(s); + } + case (h: HeapNumber): { + goto HeapNumber(h); + } + case (b: BigInt): { + goto BigInt(b); + } + case (JSAnyNotNumeric): { + x = NonNumberToNumeric(x); + } + } + } + unreachable; +} + +// Binary type switch on Number | BigInt. +macro BinaryOp1(implicit context: Context)( + leftVal: JSAny, rightVal: JSAny): never labels +Number(Number, Number), AtLeastOneBigInt(Numeric, Numeric) { + let left: JSAny = leftVal; + let right: JSAny = rightVal; + while (true) { + try { + typeswitch (left) { + case (left: Number): { + typeswitch (right) { + case (right: Number): { + goto Number(left, right); + } + case (right: BigInt): { + goto AtLeastOneBigInt(left, right); + } + case (JSAnyNotNumeric): { + goto RightNotNumeric; + } + } + } + case (left: BigInt): { + typeswitch (right) { + case (right: Numeric): { + goto AtLeastOneBigInt(left, right); + } + case (JSAnyNotNumeric): { + goto RightNotNumeric; + } + } + } + case (JSAnyNotNumeric): { + left = NonNumberToNumeric(left); + } + } + } label RightNotNumeric { + right = NonNumberToNumeric(right); + } + } + unreachable; +} + +// Binary type switch on Smi | HeapNumber | BigInt. +macro BinaryOp2(implicit context: Context)(leftVal: JSAny, rightVal: JSAny): + never labels Smis(Smi, Smi), Float64s(float64, float64), + AtLeastOneBigInt(Numeric, Numeric) { + let left: JSAny = leftVal; + let right: JSAny = rightVal; + while (true) { + try { + typeswitch (left) { + case (left: Smi): { + typeswitch (right) { + case (right: Smi): { + goto Smis(left, right); + } + case (right: HeapNumber): { + goto Float64s(SmiToFloat64(left), Convert<float64>(right)); + } + case (right: BigInt): { + goto AtLeastOneBigInt(left, right); + } + case (JSAnyNotNumeric): { + goto RightNotNumeric; + } + } + } + case (left: HeapNumber): { + typeswitch (right) { + case (right: Smi): { + goto Float64s(Convert<float64>(left), SmiToFloat64(right)); + } + case (right: HeapNumber): { + goto Float64s(Convert<float64>(left), Convert<float64>(right)); + } + case (right: BigInt): { + goto AtLeastOneBigInt(left, right); + } + case (JSAnyNotNumeric): { + goto RightNotNumeric; + } + } + } + case (left: BigInt): { + typeswitch (right) { + case (right: Numeric): { + goto AtLeastOneBigInt(left, right); + } + case (JSAnyNotNumeric): { + goto RightNotNumeric; + } + } + } + case (JSAnyNotNumeric): { + left = NonNumberToNumeric(left); + } + } + } label RightNotNumeric { + right = NonNumberToNumeric(right); + } + } + unreachable; +} + +builtin Subtract(implicit context: Context)( + left: JSAny, right: JSAny): Numeric { + try { + BinaryOp2(left, right) otherwise Smis, Float64s, AtLeastOneBigInt; + } label Smis(left: Smi, right: Smi) { + try { + return math::TrySmiSub(left, right) otherwise Overflow; + } label Overflow { + goto Float64s(SmiToFloat64(left), SmiToFloat64(right)); + } + } label Float64s(left: float64, right: float64) { + return AllocateHeapNumberWithValue(left - right); + } label AtLeastOneBigInt(left: Numeric, right: Numeric) { + tail bigint::BigIntSubtract(left, right); + } +} + +builtin Multiply(implicit context: Context)( + left: JSAny, right: JSAny): Numeric { + try { + BinaryOp2(left, right) otherwise Smis, Float64s, AtLeastOneBigInt; + } label Smis(left: Smi, right: Smi) { + // The result is not necessarily a smi, in case of overflow. + return SmiMul(left, right); + } label Float64s(left: float64, right: float64) { + return AllocateHeapNumberWithValue(left * right); + } label AtLeastOneBigInt(left: Numeric, right: Numeric) { + tail runtime::BigIntBinaryOp( + context, left, right, SmiTag<Operation>(Operation::kMultiply)); + } +} + +const kSmiValueSize: constexpr int32 generates 'kSmiValueSize'; +const kMinInt32: constexpr int32 generates 'kMinInt'; +const kMinInt31: constexpr int32 generates 'kMinInt31'; +const kMinimumDividend: int32 = (kSmiValueSize == 32) ? kMinInt32 : kMinInt31; + +builtin Divide(implicit context: Context)(left: JSAny, right: JSAny): Numeric { + try { + BinaryOp2(left, right) otherwise Smis, Float64s, AtLeastOneBigInt; + } label Smis(left: Smi, right: Smi) { + // TODO(jkummerow): Consider just always doing a double division. + // Bail out if {divisor} is zero. + if (right == 0) goto SmiBailout(left, right); + + // Bail out if dividend is zero and divisor is negative. + if (left == 0 && right < 0) goto SmiBailout(left, right); + + const dividend: int32 = SmiToInt32(left); + const divisor: int32 = SmiToInt32(right); + + // Bail out if dividend is kMinInt31 (or kMinInt32 if Smis are 32 bits) + // and divisor is -1. + if (divisor == -1 && dividend == kMinimumDividend) { + goto SmiBailout(left, right); + } + // TODO(epertoso): consider adding a machine instruction that returns + // both the result and the remainder. + const result: int32 = dividend / divisor; + const truncated: int32 = result * divisor; + if (dividend != truncated) goto SmiBailout(left, right); + return SmiFromInt32(result); + } label SmiBailout(left: Smi, right: Smi) { + goto Float64s(SmiToFloat64(left), SmiToFloat64(right)); + } label Float64s(left: float64, right: float64) { + return AllocateHeapNumberWithValue(left / right); + } label AtLeastOneBigInt(left: Numeric, right: Numeric) { + tail runtime::BigIntBinaryOp( + context, left, right, SmiTag<Operation>(Operation::kDivide)); + } +} + +builtin Modulus(implicit context: Context)(left: JSAny, right: JSAny): Numeric { + try { + BinaryOp2(left, right) otherwise Smis, Float64s, AtLeastOneBigInt; + } label Smis(left: Smi, right: Smi) { + return SmiMod(left, right); + } label Float64s(left: float64, right: float64) { + return AllocateHeapNumberWithValue(left % right); + } label AtLeastOneBigInt(left: Numeric, right: Numeric) { + tail runtime::BigIntBinaryOp( + context, left, right, SmiTag<Operation>(Operation::kModulus)); + } +} + +builtin Exponentiate(implicit context: Context)( + left: JSAny, right: JSAny): Numeric { + try { + BinaryOp1(left, right) otherwise Numbers, AtLeastOneBigInt; + } label Numbers(left: Number, right: Number) { + return math::MathPowImpl(left, right); + } label AtLeastOneBigInt(left: Numeric, right: Numeric) { + tail runtime::BigIntBinaryOp( + context, left, right, SmiTag<Operation>(Operation::kExponentiate)); + } +} + +builtin Negate(implicit context: Context)(value: JSAny): Numeric { + try { + UnaryOp2(value) otherwise Smi, HeapNumber, BigInt; + } label Smi(s: Smi) { + return SmiMul(s, -1); + } label HeapNumber(h: HeapNumber) { + return AllocateHeapNumberWithValue(Convert<float64>(h) * -1); + } label BigInt(b: BigInt) { + tail runtime::BigIntUnaryOp( + context, b, SmiTag<Operation>(Operation::kNegate)); + } +} + +builtin BitwiseNot(implicit context: Context)(value: JSAny): Numeric { + try { + UnaryOp1(value) otherwise Number, BigInt; + } label Number(n: Number) { + tail BitwiseXor(n, -1); + } label BigInt(b: BigInt) { + return runtime::BigIntUnaryOp( + context, b, SmiTag<Operation>(Operation::kBitwiseNot)); + } +} + +builtin Decrement(implicit context: Context)(value: JSAny): Numeric { + try { + UnaryOp1(value) otherwise Number, BigInt; + } label Number(n: Number) { + tail Subtract(n, 1); + } label BigInt(b: BigInt) { + return runtime::BigIntUnaryOp( + context, b, SmiTag<Operation>(Operation::kDecrement)); + } +} + +builtin Increment(implicit context: Context)(value: JSAny): Numeric { + try { + UnaryOp1(value) otherwise Number, BigInt; + } label Number(n: Number) { + tail Add(n, 1); + } label BigInt(b: BigInt) { + return runtime::BigIntUnaryOp( + context, b, SmiTag<Operation>(Operation::kIncrement)); + } +} + +// Bitwise binary operations. + +extern macro BinaryOpAssembler::Generate_BitwiseBinaryOp( + constexpr Operation, JSAny, JSAny, Context): Object; + +builtin ShiftLeft(implicit context: Context)( + left: JSAny, right: JSAny): Object { + return Generate_BitwiseBinaryOp(Operation::kShiftLeft, left, right, context); +} + +builtin ShiftRight(implicit context: Context)( + left: JSAny, right: JSAny): Object { + return Generate_BitwiseBinaryOp(Operation::kShiftRight, left, right, context); +} + +builtin ShiftRightLogical(implicit context: Context)( + left: JSAny, right: JSAny): Object { + return Generate_BitwiseBinaryOp( + Operation::kShiftRightLogical, left, right, context); +} + +builtin BitwiseAnd(implicit context: Context)( + left: JSAny, right: JSAny): Object { + return Generate_BitwiseBinaryOp(Operation::kBitwiseAnd, left, right, context); +} + +builtin BitwiseOr(implicit context: Context)( + left: JSAny, right: JSAny): Object { + return Generate_BitwiseBinaryOp(Operation::kBitwiseOr, left, right, context); } + +builtin BitwiseXor(implicit context: Context)( + left: JSAny, right: JSAny): Object { + return Generate_BitwiseBinaryOp(Operation::kBitwiseXor, left, right, context); +} + +// Relational builtins. + +builtin LessThan(implicit context: Context)(left: JSAny, right: JSAny): Object { + return RelationalComparison(Operation::kLessThan, left, right, context); +} + +builtin LessThanOrEqual(implicit context: Context)( + left: JSAny, right: JSAny): Object { + return RelationalComparison( + Operation::kLessThanOrEqual, left, right, context); +} + +builtin GreaterThan(implicit context: Context)( + left: JSAny, right: JSAny): Object { + return RelationalComparison(Operation::kGreaterThan, left, right, context); +} + +builtin GreaterThanOrEqual(implicit context: Context)( + left: JSAny, right: JSAny): Object { + return RelationalComparison( + Operation::kGreaterThanOrEqual, left, right, context); +} + +builtin Equal(implicit context: Context)(left: JSAny, right: JSAny): Object { + return Equal(left, right, context); +} + +builtin StrictEqual(implicit context: Context)( + left: JSAny, right: JSAny): Object { + return ::StrictEqual(left, right); +} + +} // namespace number diff --git a/chromium/v8/src/builtins/promise-abstract-operations.tq b/chromium/v8/src/builtins/promise-abstract-operations.tq index 9cf6da102b8..83dd56aff49 100644 --- a/chromium/v8/src/builtins/promise-abstract-operations.tq +++ b/chromium/v8/src/builtins/promise-abstract-operations.tq @@ -24,6 +24,16 @@ PromiseRejectEventFromStack(implicit context: Context)(JSPromise, JSAny): JSAny; // https://tc39.es/ecma262/#sec-promise-abstract-operations namespace promise { + +extern macro PromiseForwardingHandlerSymbolConstant(): Symbol; +const kPromiseForwardingHandlerSymbol: Symbol = + PromiseForwardingHandlerSymbolConstant(); +extern macro PromiseHandledBySymbolConstant(): Symbol; +const kPromiseHandledBySymbol: Symbol = PromiseHandledBySymbolConstant(); +extern macro ResolveStringConstant(): String; +const kResolveString: String = ResolveStringConstant(); +extern macro IsPromiseResolveProtectorCellInvalid(): bool; + extern macro AllocateFunctionWithMapAndContext( Map, SharedFunctionInfo, Context): JSFunction; @@ -503,6 +513,41 @@ PromiseGetCapabilitiesExecutor( return Undefined; } +macro IsPromiseResolveLookupChainIntact(implicit context: Context)( + nativeContext: NativeContext, constructor: JSReceiver): bool { + if (IsForceSlowPath()) return false; + const promiseFun = UnsafeCast<JSFunction>( + nativeContext[NativeContextSlot::PROMISE_FUNCTION_INDEX]); + return promiseFun == constructor && !IsPromiseResolveProtectorCellInvalid(); +} + +// https://tc39.es/ecma262/#sec-getpromiseresolve +transitioning macro GetPromiseResolve(implicit context: Context)( + nativeContext: NativeContext, constructor: Constructor): JSAny { + // 1. Assert: IsConstructor(constructor) is true. + + // We can skip the "resolve" lookup on {constructor} if it's the + // Promise constructor and the Promise.resolve protector is intact, + // as that guards the lookup path for the "resolve" property on the + // Promise constructor. In this case, promiseResolveFunction is undefined, + // and when CallResolve is called with it later, it will call Promise.resolve. + let promiseResolveFunction: JSAny = Undefined; + + if (!IsPromiseResolveLookupChainIntact(nativeContext, constructor)) { + let promiseResolve: JSAny; + + // 2. Let promiseResolve be ? Get(constructor, "resolve"). + promiseResolve = GetProperty(constructor, kResolveString); + + // 3. If IsCallable(promiseResolve) is false, throw a TypeError exception. + promiseResolveFunction = + Cast<Callable>(promiseResolve) otherwise ThrowTypeError( + MessageTemplate::kCalledNonCallable, 'resolve'); + } + // 4. return promiseResolve. + return promiseResolveFunction; +} + transitioning macro CallResolve(implicit context: Context)( constructor: Constructor, resolve: JSAny, value: JSAny): JSAny { // Undefined can never be a valid value for the resolve function, diff --git a/chromium/v8/src/builtins/promise-all-element-closure.tq b/chromium/v8/src/builtins/promise-all-element-closure.tq index 4dfafec1c92..55f722eb24d 100644 --- a/chromium/v8/src/builtins/promise-all-element-closure.tq +++ b/chromium/v8/src/builtins/promise-all-element-closure.tq @@ -66,7 +66,7 @@ extern enum PromiseAllResolveElementContextSlots extends int31 constexpr 'PromiseBuiltins::PromiseAllResolveElementContextSlots' { kPromiseAllResolveElementRemainingSlot, kPromiseAllResolveElementCapabilitySlot, - kPromiseAllResolveElementValuesArraySlot, + kPromiseAllResolveElementValuesSlot, kPromiseAllResolveElementLength } extern operator '[]=' macro StoreContextElement( @@ -106,73 +106,43 @@ transitioning macro PromiseAllResolveElementClosure<F: type>( assert(identityHash > 0); const index = identityHash - 1; - // Check if we need to grow the [[ValuesArray]] to store {value} at {index}. - const valuesArray = UnsafeCast<JSArray>( + let remainingElementsCount = + UnsafeCast<Smi>(context[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementRemainingSlot]); + + let values = + UnsafeCast<FixedArray>(context[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementValuesSlot]); + const newCapacity = index + 1; + if (newCapacity > values.length_intptr) deferred { + // This happens only when the promises are resolved during iteration. + values = ExtractFixedArray(values, 0, values.length_intptr, newCapacity); context[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementValuesArraySlot]); - const elements = UnsafeCast<FixedArray>(valuesArray.elements); - const valuesLength = Convert<intptr>(valuesArray.length); - if (index < valuesLength) { - // The {index} is in bounds of the {values_array}, check if this element has - // already been resolved, and store the {value} if not. - // - // Promise.allSettled, for each input element, has both a resolve and a - // reject closure that share an [[AlreadyCalled]] boolean. That is, the - // input element can only be settled once: after resolve is called, reject - // returns early, and vice versa. Using {function}'s context as the marker - // only tracks per-closure instead of per-element. When the second - // resolve/reject closure is called on the same index, values.object[index] - // will already exist and will not be the hole value. In that case, return - // early. Everything up to this point is not yet observable to user code. - // This is not a problem for Promise.all since Promise.all has a single - // resolve closure (no reject) per element. - if (hasResolveAndRejectClosures) { - if (elements.objects[index] != TheHole) deferred { - return Undefined; - } + kPromiseAllResolveElementValuesSlot] = values; } - // Update the value depending on whether Promise.all or - // Promise.allSettled is called. - const updatedValue = wrapResultFunctor.Call(nativeContext, value); - elements.objects[index] = updatedValue; - } else { - // Check if we need to grow the backing store. - // - // There's no need to check if this element has already been resolved for - // Promise.allSettled if {values_array} has not yet grown to the index. - const newLength = index + 1; - const elementsLength = elements.length_intptr; - - // Update the value depending on whether Promise.all or - // Promise.allSettled is called. - const updatedValue = wrapResultFunctor.Call(nativeContext, value); - - if (index < elementsLength) { - // The {index} is within bounds of the {elements} backing store, so - // just store the {value} and update the "length" of the {values_array}. - valuesArray.length = Convert<Smi>(newLength); - elements.objects[index] = updatedValue; - } else - deferred { - // We need to grow the backing store to fit the {index} as well. - const newElementsLength = IntPtrMin( - CalculateNewElementsCapacity(newLength), - kPropertyArrayHashFieldMax + 1); - assert(index < newElementsLength); - assert(elementsLength < newElementsLength); - const newElements = - ExtractFixedArray(elements, 0, elementsLength, newElementsLength); - newElements.objects[index] = updatedValue; - - // Update backing store and "length" on {values_array}. - valuesArray.elements = newElements; - valuesArray.length = Convert<Smi>(newLength); + // Promise.allSettled, for each input element, has both a resolve and a reject + // closure that share an [[AlreadyCalled]] boolean. That is, the input element + // can only be settled once: after resolve is called, reject returns early, + // and vice versa. Using {function}'s context as the marker only tracks + // per-closure instead of per-element. When the second resolve/reject closure + // is called on the same index, values.object[index] will already exist and + // will not be the hole value. In that case, return early. Everything up to + // this point is not yet observable to user code. This is not a problem for + // Promise.all since Promise.all has a single resolve closure (no reject) per + // element. + if (hasResolveAndRejectClosures) { + if (values.objects[index] != TheHole) deferred { + return Undefined; } } - let remainingElementsCount = - UnsafeCast<Smi>(context[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementRemainingSlot]); + + // Update the value depending on whether Promise.all or + // Promise.allSettled is called. + const updatedValue = wrapResultFunctor.Call(nativeContext, value); + + values.objects[index] = updatedValue; + remainingElementsCount = remainingElementsCount - 1; context[PromiseAllResolveElementContextSlots:: kPromiseAllResolveElementRemainingSlot] = remainingElementsCount; @@ -181,6 +151,9 @@ transitioning macro PromiseAllResolveElementClosure<F: type>( context[PromiseAllResolveElementContextSlots:: kPromiseAllResolveElementCapabilitySlot]); const resolve = UnsafeCast<JSAny>(capability.resolve); + const arrayMap = UnsafeCast<Map>( + nativeContext[NativeContextSlot::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX]); + const valuesArray = NewJSArray(arrayMap, values); Call(context, resolve, Undefined, valuesArray); } return Undefined; diff --git a/chromium/v8/src/builtins/promise-all.tq b/chromium/v8/src/builtins/promise-all.tq index b7fad88f6fc..302d4f3251c 100644 --- a/chromium/v8/src/builtins/promise-all.tq +++ b/chromium/v8/src/builtins/promise-all.tq @@ -18,12 +18,6 @@ const kPromiseBuiltinsPromiseContextLength: constexpr int31 // case to mark it's done). macro CreatePromiseAllResolveElementContext(implicit context: Context)( capability: PromiseCapability, nativeContext: NativeContext): Context { - // TODO(bmeurer): Manually fold this into a single allocation. - const arrayMap = UnsafeCast<Map>( - nativeContext[NativeContextSlot::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX]); - const valuesArray = AllocateJSArray( - ElementsKind::PACKED_ELEMENTS, arrayMap, IntPtrConstant(0), - SmiConstant(0)); const resolveContext = AllocateSyntheticFunctionContext( nativeContext, PromiseAllResolveElementContextSlots::kPromiseAllResolveElementLength); @@ -32,7 +26,7 @@ macro CreatePromiseAllResolveElementContext(implicit context: Context)( resolveContext[PromiseAllResolveElementContextSlots:: kPromiseAllResolveElementCapabilitySlot] = capability; resolveContext[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementValuesArraySlot] = valuesArray; + kPromiseAllResolveElementValuesSlot] = kEmptyFixedArray; return resolveContext; } @@ -115,11 +109,11 @@ struct PromiseAllSettledRejectElementFunctor { transitioning macro PerformPromiseAll<F1: type, F2: type>( implicit context: Context)( - constructor: JSReceiver, capability: PromiseCapability, - iter: iterator::IteratorRecord, createResolveElementFunctor: F1, + nativeContext: NativeContext, iter: iterator::IteratorRecord, + constructor: Constructor, capability: PromiseCapability, + promiseResolveFunction: JSAny, createResolveElementFunctor: F1, createRejectElementFunctor: F2): JSAny labels Reject(Object) { - const nativeContext = LoadNativeContext(context); const promise = capability.promise; const resolve = capability.resolve; const reject = capability.reject; @@ -135,141 +129,119 @@ Reject(Object) { let index: Smi = 1; - // We can skip the "resolve" lookup on {constructor} if it's the - // Promise constructor and the Promise.resolve protector is intact, - // as that guards the lookup path for the "resolve" property on the - // Promise constructor. - let promiseResolveFunction: JSAny = Undefined; try { - try { - if (!IsPromiseResolveLookupChainIntact(nativeContext, constructor)) { - let promiseResolve: JSAny; - - // 5. Let _promiseResolve_ be ? Get(_constructor_, `"resolve"`). - promiseResolve = GetProperty(constructor, kResolveString); - - // 6. If IsCallable(_promiseResolve_) is *false*, throw a *TypeError* - // exception. - promiseResolveFunction = - Cast<Callable>(promiseResolve) otherwise ThrowTypeError( - MessageTemplate::kCalledNonCallable, 'resolve'); + const fastIteratorResultMap = UnsafeCast<Map>( + nativeContext[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]); + while (true) { + let nextValue: JSAny; + try { + // Let next be IteratorStep(iteratorRecord.[[Iterator]]). + // If next is an abrupt completion, set iteratorRecord.[[Done]] to + // true. ReturnIfAbrupt(next). + const next: JSReceiver = iterator::IteratorStep( + iter, fastIteratorResultMap) otherwise goto Done; + + // Let nextValue be IteratorValue(next). + // If nextValue is an abrupt completion, set iteratorRecord.[[Done]] + // to true. + // ReturnIfAbrupt(nextValue). + nextValue = iterator::IteratorValue(next, fastIteratorResultMap); + } catch (e) { + goto Reject(e); } - const fastIteratorResultMap = UnsafeCast<Map>( - nativeContext[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]); - while (true) { - let nextValue: JSAny; - try { - // Let next be IteratorStep(iteratorRecord.[[Iterator]]). - // If next is an abrupt completion, set iteratorRecord.[[Done]] to - // true. ReturnIfAbrupt(next). - const next: JSReceiver = iterator::IteratorStep( - iter, fastIteratorResultMap) otherwise goto Done; - - // Let nextValue be IteratorValue(next). - // If nextValue is an abrupt completion, set iteratorRecord.[[Done]] - // to true. - // ReturnIfAbrupt(nextValue). - nextValue = iterator::IteratorValue(next, fastIteratorResultMap); - } catch (e) { - goto Reject(e); - } - - // Check if we reached the limit. - if (index == kPropertyArrayHashFieldMax) { - // If there are too many elements (currently more than 2**21-1), - // raise a RangeError here (which is caught below and turned into - // a rejection of the resulting promise). We could gracefully handle - // this case as well and support more than this number of elements - // by going to a separate function and pass the larger indices via a - // separate context, but it doesn't seem likely that we need this, - // and it's unclear how the rest of the system deals with 2**21 live - // Promises anyway. - ThrowRangeError( - MessageTemplate::kTooManyElementsInPromiseCombinator, 'all'); - } - - // Set remainingElementsCount.[[Value]] to - // remainingElementsCount.[[Value]] + 1. - const remainingElementsCount = UnsafeCast<Smi>( - resolveElementContext[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementRemainingSlot]); - resolveElementContext[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementRemainingSlot] = - remainingElementsCount + 1; - - // Let resolveElement be CreateBuiltinFunction(steps, - // « [[AlreadyCalled]], - // [[Index]], - // [[Values]], - // [[Capability]], - // [[RemainingElements]] - // »). - // Set resolveElement.[[AlreadyCalled]] to a Record { [[Value]]: false - // }. Set resolveElement.[[Index]] to index. Set - // resolveElement.[[Values]] to values. Set - // resolveElement.[[Capability]] to resultCapability. Set - // resolveElement.[[RemainingElements]] to remainingElementsCount. - const resolveElementFun = createResolveElementFunctor.Call( - resolveElementContext, nativeContext, index, capability); - const rejectElementFun = createRejectElementFunctor.Call( - resolveElementContext, nativeContext, index, capability); - - // We can skip the "resolve" lookup on the {constructor} as well as - // the "then" lookup on the result of the "resolve" call, and - // immediately chain continuation onto the {next_value} if: - // - // (a) The {constructor} is the intrinsic %Promise% function, and - // looking up "resolve" on {constructor} yields the initial - // Promise.resolve() builtin, and - // (b) the promise @@species protector cell is valid, meaning that - // no one messed with the Symbol.species property on any - // intrinsic promise or on the Promise.prototype, and - // (c) the {next_value} is a JSPromise whose [[Prototype]] field - // contains the intrinsic %PromisePrototype%, and - // (d) we're not running with async_hooks or DevTools enabled. - // - // In that case we also don't need to allocate a chained promise for - // the PromiseReaction (aka we can pass undefined to - // PerformPromiseThen), since this is only necessary for DevTools and - // PromiseHooks. - if (promiseResolveFunction != Undefined || - IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() || - IsPromiseSpeciesProtectorCellInvalid() || Is<Smi>(nextValue) || - !IsPromiseThenLookupChainIntact( - nativeContext, UnsafeCast<HeapObject>(nextValue).map)) { - // Let nextPromise be ? Call(constructor, _promiseResolve_, « - // nextValue »). - const nextPromise = CallResolve( - UnsafeCast<Constructor>(constructor), promiseResolveFunction, - nextValue); - - // Perform ? Invoke(nextPromise, "then", « resolveElement, - // resultCapability.[[Reject]] »). - const then = GetProperty(nextPromise, kThenString); - const thenResult = Call( - nativeContext, then, nextPromise, resolveElementFun, - rejectElementFun); - - // For catch prediction, mark that rejections here are - // semantically handled by the combined Promise. - if (IsDebugActive() && Is<JSPromise>(thenResult)) deferred { - SetPropertyStrict( - context, thenResult, kPromiseHandledBySymbol, promise); - } - } else { - PerformPromiseThenImpl( - UnsafeCast<JSPromise>(nextValue), resolveElementFun, - rejectElementFun, Undefined); - } - - // Set index to index + 1. - index += 1; + // Check if we reached the limit. + if (index == kPropertyArrayHashFieldMax) { + // If there are too many elements (currently more than 2**21-1), + // raise a RangeError here (which is caught below and turned into + // a rejection of the resulting promise). We could gracefully handle + // this case as well and support more than this number of elements + // by going to a separate function and pass the larger indices via a + // separate context, but it doesn't seem likely that we need this, + // and it's unclear how the rest of the system deals with 2**21 live + // Promises anyway. + ThrowRangeError( + MessageTemplate::kTooManyElementsInPromiseCombinator, 'all'); } - } catch (e) deferred { - iterator::IteratorCloseOnException(iter); - goto Reject(e); + + // Set remainingElementsCount.[[Value]] to + // remainingElementsCount.[[Value]] + 1. + const remainingElementsCount = UnsafeCast<Smi>( + resolveElementContext[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementRemainingSlot]); + resolveElementContext[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementRemainingSlot] = + remainingElementsCount + 1; + + // Let resolveElement be CreateBuiltinFunction(steps, + // « [[AlreadyCalled]], + // [[Index]], + // [[Values]], + // [[Capability]], + // [[RemainingElements]] + // »). + // Set resolveElement.[[AlreadyCalled]] to a Record { [[Value]]: false + // }. Set resolveElement.[[Index]] to index. Set + // resolveElement.[[Values]] to values. Set + // resolveElement.[[Capability]] to resultCapability. Set + // resolveElement.[[RemainingElements]] to remainingElementsCount. + const resolveElementFun = createResolveElementFunctor.Call( + resolveElementContext, nativeContext, index, capability); + const rejectElementFun = createRejectElementFunctor.Call( + resolveElementContext, nativeContext, index, capability); + + // We can skip the "then" lookup on the result of the "resolve" call and + // immediately chain the continuation onto the {next_value} if: + // + // (a) The {constructor} is the intrinsic %Promise% function, and + // looking up "resolve" on {constructor} yields the initial + // Promise.resolve() builtin, and + // (b) the promise @@species protector cell is valid, meaning that + // no one messed with the Symbol.species property on any + // intrinsic promise or on the Promise.prototype, and + // (c) the {next_value} is a JSPromise whose [[Prototype]] field + // contains the intrinsic %PromisePrototype%, and + // (d) we're not running with async_hooks or DevTools enabled. + // + // In that case we also don't need to allocate a chained promise for + // the PromiseReaction (aka we can pass undefined to + // PerformPromiseThen), since this is only necessary for DevTools and + // PromiseHooks. + if (promiseResolveFunction != Undefined || + IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() || + IsPromiseSpeciesProtectorCellInvalid() || Is<Smi>(nextValue) || + !IsPromiseThenLookupChainIntact( + nativeContext, UnsafeCast<HeapObject>(nextValue).map)) { + // Let nextPromise be ? Call(constructor, _promiseResolve_, « + // nextValue »). + const nextPromise = + CallResolve(constructor, promiseResolveFunction, nextValue); + + // Perform ? Invoke(nextPromise, "then", « resolveElement, + // resultCapability.[[Reject]] »). + const then = GetProperty(nextPromise, kThenString); + const thenResult = Call( + nativeContext, then, nextPromise, resolveElementFun, + rejectElementFun); + + // For catch prediction, mark that rejections here are + // semantically handled by the combined Promise. + if (IsDebugActive() && Is<JSPromise>(thenResult)) deferred { + SetPropertyStrict( + context, thenResult, kPromiseHandledBySymbol, promise); + } + } else { + PerformPromiseThenImpl( + UnsafeCast<JSPromise>(nextValue), resolveElementFun, + rejectElementFun, Undefined); + } + + // Set index to index + 1. + index += 1; } + } catch (e) deferred { + iterator::IteratorCloseOnException(iter); + goto Reject(e); } label Done {} // Set iteratorRecord.[[Done]] to true. @@ -283,30 +255,36 @@ Reject(Object) { kPromiseAllResolveElementRemainingSlot] = remainingElementsCount; if (remainingElementsCount > 0) { - // Pre-allocate the backing store for the {values_array} to the desired - // capacity here. We may already have elements here in case of some - // fancy Thenable that calls the resolve callback immediately, so we need - // to handle that correctly here. - const valuesArray = UnsafeCast<JSArray>( + // Pre-allocate the backing store for the {values} to the desired + // capacity. We may already have elements in "values" - this happens + // when the Thenable calls the resolve callback immediately. + let values = UnsafeCast<FixedArray>( resolveElementContext[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementValuesArraySlot]); - const oldElements = UnsafeCast<FixedArray>(valuesArray.elements); - const oldCapacity = oldElements.length_intptr; - const newCapacity = SmiUntag(index); + kPromiseAllResolveElementValuesSlot]); + // 'index' is a 1-based index and incremented after every Promise. Later we + // use 'values' as a 0-based array, so capacity 'index - 1' is enough. + const newCapacity = SmiUntag(index) - 1; + + const oldCapacity = values.length_intptr; if (oldCapacity < newCapacity) { - valuesArray.elements = - ExtractFixedArray(oldElements, 0, oldCapacity, newCapacity); + values = ExtractFixedArray(values, 0, oldCapacity, newCapacity); + resolveElementContext[PromiseAllResolveElementContextSlots:: + kPromiseAllResolveElementValuesSlot] = values; } } else deferred { + assert(remainingElementsCount == 0); // If remainingElementsCount.[[Value]] is 0, then // Let valuesArray be CreateArrayFromList(values). // Perform ? Call(resultCapability.[[Resolve]], undefined, // « valuesArray »). - assert(remainingElementsCount == 0); - const valuesArray = UnsafeCast<JSAny>( + + const values = UnsafeCast<FixedArray>( resolveElementContext[PromiseAllResolveElementContextSlots:: - kPromiseAllResolveElementValuesArraySlot]); + kPromiseAllResolveElementValuesSlot]); + const arrayMap = UnsafeCast<Map>( + nativeContext[NativeContextSlot::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX]); + const valuesArray = NewJSArray(arrayMap, values); Call(nativeContext, UnsafeCast<JSAny>(resolve), Undefined, valuesArray); } @@ -318,6 +296,7 @@ transitioning macro GeneratePromiseAll<F1: type, F2: type>( implicit context: Context)( receiver: JSAny, iterable: JSAny, createResolveElementFunctor: F1, createRejectElementFunctor: F2): JSAny { + const nativeContext = LoadNativeContext(context); // Let C be the this value. // If Type(C) is not Object, throw a TypeError exception. const receiver = Cast<JSReceiver>(receiver) @@ -328,7 +307,16 @@ transitioning macro GeneratePromiseAll<F1: type, F2: type>( // not trigger redundant ExceptionEvents const capability = NewPromiseCapability(receiver, False); + // NewPromiseCapability guarantees that receiver is Constructor. + assert(Is<Constructor>(receiver)); + const constructor = UnsafeCast<Constructor>(receiver); + try { + // Let promiseResolve be GetPromiseResolve(C). + // IfAbruptRejectPromise(promiseResolve, promiseCapability). + const promiseResolveFunction = + GetPromiseResolve(nativeContext, constructor); + // Let iterator be GetIterator(iterable). // IfAbruptRejectPromise(iterator, promiseCapability). let i = iterator::GetIterator(iterable); @@ -339,8 +327,9 @@ transitioning macro GeneratePromiseAll<F1: type, F2: type>( // IteratorClose(iterator, result). // IfAbruptRejectPromise(result, promiseCapability). return PerformPromiseAll( - receiver, capability, i, createResolveElementFunctor, - createRejectElementFunctor) otherwise Reject; + nativeContext, i, constructor, capability, promiseResolveFunction, + createResolveElementFunctor, createRejectElementFunctor) + otherwise Reject; } catch (e) deferred { goto Reject(e); } label Reject(e: Object) deferred { diff --git a/chromium/v8/src/builtins/promise-any.tq b/chromium/v8/src/builtins/promise-any.tq index 1046ed0a89c..2fefdf4baad 100644 --- a/chromium/v8/src/builtins/promise-any.tq +++ b/chromium/v8/src/builtins/promise-any.tq @@ -9,7 +9,7 @@ extern enum PromiseAnyRejectElementContextSlots extends int31 constexpr 'PromiseBuiltins::PromiseAnyRejectElementContextSlots' { kPromiseAnyRejectElementRemainingSlot, kPromiseAnyRejectElementCapabilitySlot, - kPromiseAnyRejectElementErrorsArraySlot, + kPromiseAnyRejectElementErrorsSlot, kPromiseAnyRejectElementLength } @@ -35,9 +35,8 @@ transitioning macro CreatePromiseAnyRejectElementContext( kPromiseAnyRejectElementRemainingSlot] = SmiConstant(1); rejectContext[PromiseAnyRejectElementContextSlots:: kPromiseAnyRejectElementCapabilitySlot] = capability; - // Will be set later. rejectContext[PromiseAnyRejectElementContextSlots:: - kPromiseAnyRejectElementErrorsArraySlot] = Undefined; + kPromiseAnyRejectElementErrorsSlot] = kEmptyFixedArray; return rejectContext; } @@ -92,17 +91,9 @@ PromiseAnyRejectElementClosure( const index = identityHash - 1; // 6. Let errors be F.[[Errors]]. - if (context[PromiseAnyRejectElementContextSlots:: - kPromiseAnyRejectElementErrorsArraySlot] == Undefined) { - // We're going to reject the Promise with a more fundamental error (e.g., - // something went wrong with iterating the Promises). We don't need to - // construct the "errors" array. - return Undefined; - } - - const errorsArray = UnsafeCast<FixedArray>( - context[PromiseAnyRejectElementContextSlots:: - kPromiseAnyRejectElementErrorsArraySlot]); + let errors = + UnsafeCast<FixedArray>(context[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementErrorsSlot]); // 7. Let promiseCapability be F.[[Capability]]. @@ -110,8 +101,15 @@ PromiseAnyRejectElementClosure( let remainingElementsCount = UnsafeCast<Smi>(context[PromiseAnyRejectElementContextSlots:: kPromiseAnyRejectElementRemainingSlot]); + // 9. Set errors[index] to x. - errorsArray.objects[index] = value; + const newCapacity = IntPtrMax(SmiUntag(remainingElementsCount), index + 1); + if (newCapacity > errors.length_intptr) deferred { + errors = ExtractFixedArray(errors, 0, errors.length_intptr, newCapacity); + context[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementErrorsSlot] = errors; + } + errors.objects[index] = value; // 10. Set remainingElementsCount.[[Value]] to // remainingElementsCount.[[Value]] - 1. @@ -124,7 +122,7 @@ PromiseAnyRejectElementClosure( // a. Let error be a newly created AggregateError object. // b. Set error.[[AggregateErrors]] to errors. - const error = ConstructAggregateError(errorsArray); + const error = ConstructAggregateError(errors); // c. Return ? Call(promiseCapability.[[Reject]], undefined, « error »). const capability = UnsafeCast<PromiseCapability>( context[PromiseAnyRejectElementContextSlots:: @@ -137,16 +135,15 @@ PromiseAnyRejectElementClosure( } transitioning macro PerformPromiseAny(implicit context: Context)( - iteratorRecord: iterator::IteratorRecord, constructor: Constructor, - resultCapability: PromiseCapability): JSAny labels + nativeContext: NativeContext, iteratorRecord: iterator::IteratorRecord, + constructor: Constructor, resultCapability: PromiseCapability, + promiseResolveFunction: JSAny): JSAny labels Reject(Object) { // 1. Assert: ! IsConstructor(constructor) is true. // 2. Assert: resultCapability is a PromiseCapability Record. - const nativeContext = LoadNativeContext(context); - - // 3. Let errors be a new empty List. - let growableErrorsArray = growable_fixed_array::NewGrowableFixedArray(); + // 3. Let errors be a new empty List. (Do nothing: errors is + // initialized lazily when the first Promise rejects.) // 4. Let remainingElementsCount be a new Record { [[Value]]: 1 }. const rejectElementContext = @@ -157,21 +154,6 @@ Reject(Object) { let index: Smi = 1; try { - // We can skip the "resolve" lookup on {constructor} if it's the - // Promise constructor and the Promise.resolve protector is intact, - // as that guards the lookup path for the "resolve" property on the - // Promise constructor. - let promiseResolveFunction: JSAny = Undefined; - if (!IsPromiseResolveLookupChainIntact(nativeContext, constructor)) - deferred { - // 6. Let promiseResolve be ? Get(constructor, `"resolve"`). - const promiseResolve = GetProperty(constructor, kResolveString); - // 7. If IsCallable(promiseResolve) is false, throw a - // TypeError exception. - promiseResolveFunction = Cast<Callable>(promiseResolve) - otherwise ThrowTypeError( - MessageTemplate::kCalledNonCallable, 'resolve'); - } const fastIteratorResultMap = UnsafeCast<Map>( nativeContext[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]); // 8. Repeat, @@ -215,8 +197,8 @@ Reject(Object) { MessageTemplate::kTooManyElementsInPromiseCombinator, 'any'); } - // h. Append undefined to errors. - growableErrorsArray.Push(Undefined); + // h. Append undefined to errors. (Do nothing: errors is initialized + // lazily when the first Promise rejects.) let nextPromise: JSAny; // i. Let nextPromise be ? Call(constructor, promiseResolve, @@ -291,16 +273,18 @@ Reject(Object) { kPromiseAnyRejectElementRemainingSlot] = remainingElementsCount; - const errorsArray = growableErrorsArray.ToFixedArray(); - rejectElementContext[PromiseAnyRejectElementContextSlots:: - kPromiseAnyRejectElementErrorsArraySlot] = - errorsArray; - // iii. If remainingElementsCount.[[Value]] is 0, then if (remainingElementsCount == 0) deferred { // 1. Let error be a newly created AggregateError object. // 2. Set error.[[AggregateErrors]] to errors. - const error = ConstructAggregateError(errorsArray); + + // We may already have elements in "errors" - this happens when the + // Thenable calls the reject callback immediately. + const errors = UnsafeCast<FixedArray>( + rejectElementContext[PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementErrorsSlot]); + + const error = ConstructAggregateError(errors); // 3. Return ThrowCompletion(error). goto Reject(error); } @@ -312,6 +296,8 @@ Reject(Object) { transitioning javascript builtin PromiseAny( js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny { + const nativeContext = LoadNativeContext(context); + // 1. Let C be the this value. const receiver = Cast<JSReceiver>(receiver) otherwise ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'Promise.any'); @@ -319,37 +305,42 @@ PromiseAny( // 2. Let promiseCapability be ? NewPromiseCapability(C). const capability = NewPromiseCapability(receiver, False); - // NewPromiseCapability guarantees that receiver is Constructor + // NewPromiseCapability guarantees that receiver is Constructor. assert(Is<Constructor>(receiver)); const constructor = UnsafeCast<Constructor>(receiver); try { - let iteratorRecord: iterator::IteratorRecord; - try { - // 3. Let iteratorRecord be GetIterator(iterable). + // 3. Let promiseResolve be GetPromiseResolve(C). + // 4. IfAbruptRejectPromise(promiseResolve, promiseCapability). + // (catch below) + const promiseResolveFunction = + GetPromiseResolve(nativeContext, constructor); - // 4. IfAbruptRejectPromise(iteratorRecord, promiseCapability). - // (catch below) - iteratorRecord = iterator::GetIterator(iterable); + // 5. Let iteratorRecord be GetIterator(iterable). - // 5. Let result be PerformPromiseAny(iteratorRecord, C, - // promiseCapability). + // 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability). + // (catch below) + const iteratorRecord = iterator::GetIterator(iterable); - // 6. If result is an abrupt completion, then + // 7. Let result be PerformPromiseAny(iteratorRecord, C, + // promiseCapability). - // a. If iteratorRecord.[[Done]] is false, set result to - // IteratorClose(iteratorRecord, result). + // 8. If result is an abrupt completion, then - // b. IfAbruptRejectPromise(result, promiseCapability). + // a. If iteratorRecord.[[Done]] is false, set result to + // IteratorClose(iteratorRecord, result). - // [Iterator closing handled by PerformPromiseAny] + // b. IfAbruptRejectPromise(result, promiseCapability). - // 7. Return Completion(result). - return PerformPromiseAny(iteratorRecord, constructor, capability) - otherwise Reject; - } catch (e) deferred { - goto Reject(e); - } + // [Iterator closing handled by PerformPromiseAny] + + // 9. Return Completion(result). + return PerformPromiseAny( + nativeContext, iteratorRecord, constructor, capability, + promiseResolveFunction) + otherwise Reject; + } catch (e) deferred { + goto Reject(e); } label Reject(e: Object) deferred { // Exception must be bound to a JS value. assert(e != TheHole); @@ -361,10 +352,13 @@ PromiseAny( } transitioning macro ConstructAggregateError(implicit context: Context)( - errorsArray: FixedArray): JSObject { - const obj: JSAggregateError = error::ConstructInternalAggregateErrorHelper( + errors: FixedArray): JSObject { + const obj: JSObject = error::ConstructInternalAggregateErrorHelper( context, SmiConstant(MessageTemplate::kAllPromisesRejected)); - obj.errors = errorsArray; + const errorsJSArray = array::CreateJSArrayWithElements(errors); + SetOwnPropertyIgnoreAttributes( + obj, ErrorsStringConstant(), errorsJSArray, + SmiConstant(PropertyAttributes::DONT_ENUM)); return obj; } diff --git a/chromium/v8/src/builtins/promise-race.tq b/chromium/v8/src/builtins/promise-race.tq index 27d2038398a..26ffb7ae554 100644 --- a/chromium/v8/src/builtins/promise-race.tq +++ b/chromium/v8/src/builtins/promise-race.tq @@ -6,24 +6,6 @@ namespace promise { -extern macro PromiseForwardingHandlerSymbolConstant(): Symbol; -const kPromiseForwardingHandlerSymbol: Symbol = - PromiseForwardingHandlerSymbolConstant(); -extern macro PromiseHandledBySymbolConstant(): Symbol; -const kPromiseHandledBySymbol: Symbol = PromiseHandledBySymbolConstant(); -extern macro ResolveStringConstant(): String; -const kResolveString: String = ResolveStringConstant(); -extern macro SetPropertyStrict(Context, Object, Object, Object): Object; -extern macro IsPromiseResolveProtectorCellInvalid(): bool; - -macro IsPromiseResolveLookupChainIntact(implicit context: Context)( - nativeContext: NativeContext, constructor: JSReceiver): bool { - if (IsForceSlowPath()) return false; - const promiseFun = UnsafeCast<JSFunction>( - nativeContext[NativeContextSlot::PROMISE_FUNCTION_INDEX]); - return promiseFun == constructor && !IsPromiseResolveProtectorCellInvalid(); -} - // https://tc39.es/ecma262/#sec-promise.race transitioning javascript builtin PromiseRace( @@ -31,6 +13,8 @@ PromiseRace( const receiver = Cast<JSReceiver>(receiver) otherwise ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'Promise.race'); + const nativeContext = LoadNativeContext(context); + // Let promiseCapability be ? NewPromiseCapability(C). // Don't fire debugEvent so that forwarding the rejection through all does // not trigger redundant ExceptionEvents @@ -39,6 +23,10 @@ PromiseRace( const reject = capability.reject; const promise = capability.promise; + // NewPromiseCapability guarantees that receiver is Constructor. + assert(Is<Constructor>(receiver)); + const constructor = UnsafeCast<Constructor>(receiver); + // For catch prediction, don't treat the .then calls as handling it; // instead, recurse outwards. if (IsDebugActive()) deferred { @@ -46,10 +34,15 @@ PromiseRace( } try { - // Let iterator be GetIterator(iterable). - // IfAbruptRejectPromise(iterator, promiseCapability). + let promiseResolveFunction: JSAny; let i: iterator::IteratorRecord; try { + // Let promiseResolve be GetPromiseResolve(C). + // IfAbruptRejectPromise(promiseResolve, promiseCapability). + promiseResolveFunction = GetPromiseResolve(nativeContext, constructor); + + // Let iterator be GetIterator(iterable). + // IfAbruptRejectPromise(iterator, promiseCapability). i = iterator::GetIterator(iterable); } catch (e) deferred { goto Reject(e); @@ -57,24 +50,6 @@ PromiseRace( // Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability). try { - // We can skip the "resolve" lookup on {constructor} if it's the - // Promise constructor and the Promise.resolve protector is intact, - // as that guards the lookup path for the "resolve" property on the - // Promise constructor. - const nativeContext = LoadNativeContext(context); - let promiseResolveFunction: JSAny = Undefined; - if (!IsPromiseResolveLookupChainIntact(nativeContext, receiver)) - deferred { - // 3. Let _promiseResolve_ be ? Get(_constructor_, `"resolve"`). - const resolve = GetProperty(receiver, kResolveString); - - // 4. If IsCallable(_promiseResolve_) is *false*, throw a - // *TypeError* exception. - promiseResolveFunction = Cast<Callable>(resolve) - otherwise ThrowTypeError( - MessageTemplate::kCalledNonCallable, 'resolve'); - } - const fastIteratorResultMap = UnsafeCast<Map>( nativeContext[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]); while (true) { @@ -96,9 +71,8 @@ PromiseRace( } // Let nextPromise be ? Call(constructor, _promiseResolve_, « // nextValue »). - const nextPromise = CallResolve( - UnsafeCast<Constructor>(receiver), promiseResolveFunction, - nextValue); + const nextPromise = + CallResolve(constructor, promiseResolveFunction, nextValue); // Perform ? Invoke(nextPromise, "then", « resolveElement, // resultCapability.[[Reject]] »). diff --git a/chromium/v8/src/builtins/regexp.tq b/chromium/v8/src/builtins/regexp.tq index 21577b47634..603b456661d 100644 --- a/chromium/v8/src/builtins/regexp.tq +++ b/chromium/v8/src/builtins/regexp.tq @@ -186,8 +186,7 @@ extern enum Flag constexpr 'JSRegExp::Flag' { kMultiline, kSticky, kUnicode, - kDotAll, - kInvalid + kDotAll } const kRegExpPrototypeOldFlagGetter: constexpr int31 diff --git a/chromium/v8/src/builtins/setup-builtins-internal.cc b/chromium/v8/src/builtins/setup-builtins-internal.cc index 4739e18c57f..d094c3f2ad4 100644 --- a/chromium/v8/src/builtins/setup-builtins-internal.cc +++ b/chromium/v8/src/builtins/setup-builtins-internal.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "src/init/setup-isolate.h" - #include "src/builtins/builtins.h" #include "src/codegen/assembler-inl.h" #include "src/codegen/interface-descriptors.h" @@ -12,7 +10,8 @@ #include "src/compiler/code-assembler.h" #include "src/execution/isolate.h" #include "src/handles/handles-inl.h" -#include "src/heap/heap-inl.h" // For MemoryAllocator::code_range. +#include "src/heap/heap-inl.h" // For Heap::code_range. +#include "src/init/setup-isolate.h" #include "src/interpreter/bytecodes.h" #include "src/interpreter/interpreter-generator.h" #include "src/interpreter/interpreter.h" diff --git a/chromium/v8/src/builtins/torque-internal.tq b/chromium/v8/src/builtins/torque-internal.tq index d2b107f932d..5a75f5ca726 100644 --- a/chromium/v8/src/builtins/torque-internal.tq +++ b/chromium/v8/src/builtins/torque-internal.tq @@ -186,6 +186,28 @@ macro StoreFloat64OrHole(r:&float64_or_hole, value: float64_or_hole) { * unsafe::NewReference<float64>(r.object, r.offset) = value.value; } } + +macro DownCastForTorqueClass<T : type extends HeapObject>(o: HeapObject): + T labels CastError { + const map = o.map; + const minInstanceType = %MinInstanceType<T>(); + const maxInstanceType = %MaxInstanceType<T>(); + if constexpr (minInstanceType == maxInstanceType) { + if constexpr (%ClassHasMapConstant<T>()) { + if (map != %GetClassMapConstant<T>()) goto CastError; + } else { + if (map.instance_type != minInstanceType) goto CastError; + } + } else { + const diff: int32 = maxInstanceType - minInstanceType; + const offset = Convert<int32>(Convert<uint16>(map.instance_type)) - + Convert<int32>(Convert<uint16>( + FromConstexpr<InstanceType>(minInstanceType))); + if (Unsigned(offset) > Unsigned(diff)) goto CastError; + } + return %RawDownCast<T>(o); +} + } // namespace torque_internal // Indicates that an array-field should not be initialized. @@ -198,6 +220,12 @@ struct UninitializedIterator {} intrinsic %RawDownCast<To: type, From: type>(x: From): To; intrinsic %RawConstexprCast<To: type, From: type>(f: From): To; +intrinsic %MinInstanceType<T: type>(): constexpr InstanceType; +intrinsic %MaxInstanceType<T: type>(): constexpr InstanceType; + +intrinsic %ClassHasMapConstant<T: type>(): constexpr bool; +intrinsic %GetClassMapConstant<T: type>(): Map; + struct IteratorSequence<T: type, FirstIterator: type, SecondIterator: type> { macro Empty(): bool { return this.first.Empty() && this.second.Empty(); diff --git a/chromium/v8/src/builtins/typed-array-entries.tq b/chromium/v8/src/builtins/typed-array-entries.tq new file mode 100644 index 00000000000..6749a14e90a --- /dev/null +++ b/chromium/v8/src/builtins/typed-array-entries.tq @@ -0,0 +1,27 @@ +// Copyright 2019 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include 'src/builtins/builtins-typed-array-gen.h' + +namespace typed_array { +const kBuiltinNameEntries: constexpr string = '%TypedArray%.prototype.entries'; + +// %TypedArray%.entries () +// https://tc39.github.io/ecma262/#sec-%typedarray%.entries +transitioning javascript builtin +TypedArrayPrototypeEntries(js-implicit context: NativeContext, receiver: JSAny)( + ...arguments): JSArrayIterator { + try { + const array: JSTypedArray = Cast<JSTypedArray>(receiver) + otherwise NotTypedArray; + + EnsureAttached(array) otherwise IsDetached; + return CreateArrayIterator(array, IterationKind::kEntries); + } label NotTypedArray deferred { + ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameEntries); + } label IsDetached deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameEntries); + } +} +} diff --git a/chromium/v8/src/builtins/typed-array-keys.tq b/chromium/v8/src/builtins/typed-array-keys.tq new file mode 100644 index 00000000000..24c53c71052 --- /dev/null +++ b/chromium/v8/src/builtins/typed-array-keys.tq @@ -0,0 +1,27 @@ +// Copyright 2019 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include 'src/builtins/builtins-typed-array-gen.h' + +namespace typed_array { +const kBuiltinNameKeys: constexpr string = '%TypedArray%.prototype.keys'; + +// %TypedArray%.keys () +// https://tc39.github.io/ecma262/#sec-%typedarray%.keys +transitioning javascript builtin +TypedArrayPrototypeKeys(js-implicit context: NativeContext, receiver: JSAny)( + ...arguments): JSArrayIterator { + try { + const array: JSTypedArray = Cast<JSTypedArray>(receiver) + otherwise NotTypedArray; + + EnsureAttached(array) otherwise IsDetached; + return CreateArrayIterator(array, IterationKind::kKeys); + } label NotTypedArray deferred { + ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameKeys); + } label IsDetached deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameKeys); + } +} +} diff --git a/chromium/v8/src/builtins/typed-array-values.tq b/chromium/v8/src/builtins/typed-array-values.tq new file mode 100644 index 00000000000..a60aaaf707f --- /dev/null +++ b/chromium/v8/src/builtins/typed-array-values.tq @@ -0,0 +1,27 @@ +// Copyright 2019 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include 'src/builtins/builtins-typed-array-gen.h' + +namespace typed_array { +const kBuiltinNameValues: constexpr string = '%TypedArray%.prototype.values'; + +// %TypedArray%.values () +// https://tc39.github.io/ecma262/#sec-%typedarray%.values +transitioning javascript builtin +TypedArrayPrototypeValues(js-implicit context: NativeContext, receiver: JSAny)( + ...arguments): JSArrayIterator { + try { + const array: JSTypedArray = Cast<JSTypedArray>(receiver) + otherwise NotTypedArray; + + EnsureAttached(array) otherwise IsDetached; + return CreateArrayIterator(array, IterationKind::kValues); + } label NotTypedArray deferred { + ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameValues); + } label IsDetached deferred { + ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameValues); + } +} +} diff --git a/chromium/v8/src/builtins/wasm.tq b/chromium/v8/src/builtins/wasm.tq index 097e39d430e..690df7afecc 100644 --- a/chromium/v8/src/builtins/wasm.tq +++ b/chromium/v8/src/builtins/wasm.tq @@ -7,6 +7,10 @@ namespace runtime { extern runtime WasmMemoryGrow(Context, WasmInstanceObject, Smi): Smi; extern runtime WasmRefFunc(Context, WasmInstanceObject, Smi): JSAny; +extern runtime WasmTableInit( + Context, WasmInstanceObject, Object, Object, Smi, Smi, Smi): JSAny; +extern runtime WasmTableCopy( + Context, WasmInstanceObject, Object, Object, Smi, Smi, Smi): JSAny; extern runtime WasmFunctionTableGet( Context, WasmInstanceObject, Smi, Smi): JSAny; extern runtime WasmFunctionTableSet( @@ -17,11 +21,24 @@ extern runtime ReThrow(Context, Object): JSAny; extern runtime WasmStackGuard(Context): JSAny; extern runtime ThrowWasmStackOverflow(Context): JSAny; extern runtime WasmTraceMemory(Context, Smi): JSAny; +extern runtime WasmTraceEnter(Context): JSAny; +extern runtime WasmTraceExit(Context, Smi): JSAny; +extern runtime WasmAtomicNotify( + Context, WasmInstanceObject, Number, Number): Smi; +extern runtime WasmI32AtomicWait( + Context, WasmInstanceObject, Number, Number, BigInt): Smi; +extern runtime WasmI64AtomicWait( + Context, WasmInstanceObject, Number, BigInt, BigInt): Smi; +} + +namespace unsafe { +extern macro TimesTaggedSize(intptr): intptr; +extern macro Allocate(intptr): HeapObject; } namespace wasm { const kFuncTableType: - constexpr int31 generates 'wasm::ValueType::Kind::kFuncRef'; + constexpr int31 generates 'wasm::HeapType::kHeapFunc'; extern macro WasmBuiltinsAssembler::LoadInstanceFromFrame(): WasmInstanceObject; @@ -33,6 +50,8 @@ extern macro WasmBuiltinsAssembler::LoadTablesFromInstance(WasmInstanceObject): FixedArray; extern macro WasmBuiltinsAssembler::LoadExternalFunctionsFromInstance( WasmInstanceObject): FixedArray; +extern macro WasmBuiltinsAssembler::LoadManagedObjectMapsFromInstance( + WasmInstanceObject): FixedArray; macro LoadContextFromFrame(): NativeContext { return LoadContextFromInstance(LoadInstanceFromFrame()); @@ -61,6 +80,38 @@ builtin WasmMemoryGrow(numPages: int32): int32 { return SmiToInt32(result); } +builtin WasmTableInit( + dstRaw: uint32, srcRaw: uint32, sizeRaw: uint32, tableIndex: Smi, + segmentIndex: Smi): JSAny { + try { + const instance: WasmInstanceObject = LoadInstanceFromFrame(); + const dst: Smi = Convert<PositiveSmi>(dstRaw) otherwise TableOutOfBounds; + const src: Smi = Convert<PositiveSmi>(srcRaw) otherwise TableOutOfBounds; + const size: Smi = Convert<PositiveSmi>(sizeRaw) otherwise TableOutOfBounds; + tail runtime::WasmTableInit( + LoadContextFromInstance(instance), instance, tableIndex, segmentIndex, + dst, src, size); + } label TableOutOfBounds deferred { + tail ThrowWasmTrapTableOutOfBounds(); + } +} + +builtin WasmTableCopy( + dstRaw: uint32, srcRaw: uint32, sizeRaw: uint32, dstTable: Smi, + srcTable: Smi): JSAny { + try { + const instance: WasmInstanceObject = LoadInstanceFromFrame(); + const dst: Smi = Convert<PositiveSmi>(dstRaw) otherwise TableOutOfBounds; + const src: Smi = Convert<PositiveSmi>(srcRaw) otherwise TableOutOfBounds; + const size: Smi = Convert<PositiveSmi>(sizeRaw) otherwise TableOutOfBounds; + tail runtime::WasmTableCopy( + LoadContextFromInstance(instance), instance, dstTable, srcTable, dst, + src, size); + } label TableOutOfBounds deferred { + tail ThrowWasmTrapTableOutOfBounds(); + } +} + builtin WasmTableGet(tableIndex: intptr, index: int32): Object { const instance: WasmInstanceObject = LoadInstanceFromFrame(); const entryIndex: intptr = ChangeInt32ToIntPtr(index); @@ -145,7 +196,7 @@ builtin WasmThrow(exception: Object): JSAny { } builtin WasmRethrow(exception: Object): JSAny { - if (exception == Null) tail ThrowWasmTrapRethrowNullRef(); + if (exception == Null) tail ThrowWasmTrapRethrowNull(); tail runtime::ReThrow(LoadContextFromFrame(), exception); } @@ -161,11 +212,77 @@ builtin WasmTraceMemory(info: Smi): JSAny { tail runtime::WasmTraceMemory(LoadContextFromFrame(), info); } +builtin WasmTraceEnter(): JSAny { + tail runtime::WasmTraceEnter(LoadContextFromFrame()); +} + +builtin WasmTraceExit(info: Smi): JSAny { + tail runtime::WasmTraceExit(LoadContextFromFrame(), info); +} + builtin WasmAllocateJSArray(implicit context: Context)(size: Smi): JSArray { const map: Map = GetFastPackedElementsJSArrayMap(); return AllocateJSArray(ElementsKind::PACKED_ELEMENTS, map, size, size); } +builtin WasmAllocateStruct(implicit context: Context)(mapIndex: Smi): + HeapObject { + const instance: WasmInstanceObject = LoadInstanceFromFrame(); + const maps: FixedArray = LoadManagedObjectMapsFromInstance(instance); + const map: Map = %RawDownCast<Map>(LoadFixedArrayElement(maps, mapIndex)); + const instanceSize: intptr = + unsafe::TimesTaggedSize(Convert<intptr>(map.instance_size_in_words)); + const result: HeapObject = unsafe::Allocate(instanceSize); + * UnsafeConstCast(& result.map) = map; + return result; +} + +builtin WasmInt32ToNumber(value: int32): Number { + return ChangeInt32ToTagged(value); +} + +builtin WasmUint32ToNumber(value: uint32): Number { + return ChangeUint32ToTagged(value); +} + +extern builtin I64ToBigInt(intptr): BigInt; + +builtin WasmAtomicNotify(address: uint32, count: uint32): uint32 { + const instance: WasmInstanceObject = LoadInstanceFromFrame(); + const result: Smi = runtime::WasmAtomicNotify( + LoadContextFromInstance(instance), instance, WasmUint32ToNumber(address), + WasmUint32ToNumber(count)); + return Unsigned(SmiToInt32(result)); +} + +builtin WasmI32AtomicWait64( + address: uint32, expectedValue: int32, timeout: intptr): uint32 { + if constexpr (Is64()) { + const instance: WasmInstanceObject = LoadInstanceFromFrame(); + const result: Smi = runtime::WasmI32AtomicWait( + LoadContextFromInstance(instance), instance, + WasmUint32ToNumber(address), WasmInt32ToNumber(expectedValue), + I64ToBigInt(timeout)); + return Unsigned(SmiToInt32(result)); + } else { + unreachable; + } +} + +builtin WasmI64AtomicWait64( + address: uint32, expectedValue: intptr, timeout: intptr): uint32 { + if constexpr (Is64()) { + const instance: WasmInstanceObject = LoadInstanceFromFrame(); + const result: Smi = runtime::WasmI64AtomicWait( + LoadContextFromInstance(instance), instance, + WasmUint32ToNumber(address), I64ToBigInt(expectedValue), + I64ToBigInt(timeout)); + return Unsigned(SmiToInt32(result)); + } else { + unreachable; + } +} + extern macro TryHasOwnProperty(HeapObject, Map, InstanceType, Name): never labels Found, NotFound, Bailout; type OnNonExistent constexpr 'OnNonExistent'; @@ -251,12 +368,12 @@ builtin ThrowWasmTrapTableOutOfBounds(): JSAny { tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapTableOutOfBounds)); } -builtin ThrowWasmTrapBrOnExnNullRef(): JSAny { - tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapBrOnExnNullRef)); +builtin ThrowWasmTrapBrOnExnNull(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapBrOnExnNull)); } -builtin ThrowWasmTrapRethrowNullRef(): JSAny { - tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapRethrowNullRef)); +builtin ThrowWasmTrapRethrowNull(): JSAny { + tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapRethrowNull)); } builtin ThrowWasmTrapNullDereference(): JSAny { |