From 20f6f21cae129d156329285fee3242a60ba6d567 Mon Sep 17 00:00:00 2001 From: Igor Sheludko Date: Wed, 13 Nov 2019 20:37:22 +0100 Subject: [PATCH] [builtins] Ensure constructor has a prototype slot Drive-by-cleanup: simplify related helper functions in CSA. Bug: chromium:1022855 Change-Id: Icb15e6a35275708af313ec5776e92be4b6ce2524 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1910939 Commit-Queue: Igor Sheludko Reviewed-by: Toon Verwaest Cr-Commit-Position: refs/heads/master@{#64961} --- src/builtins/builtins-constructor-gen.cc | 11 +++--- src/builtins/cast.tq | 8 ++++ src/codegen/code-stub-assembler.cc | 50 +++++++++--------------- src/codegen/code-stub-assembler.h | 27 +++++++++++-- src/diagnostics/objects-debug.cc | 3 ++ src/objects/js-objects.tq | 8 ++-- 6 files changed, 61 insertions(+), 46 deletions(-) diff --git a/src/builtins/builtins-constructor-gen.cc b/src/builtins/builtins-constructor-gen.cc index 38159ee3b2..50d2810355 100644 --- a/src/builtins/builtins-constructor-gen.cc +++ b/src/builtins/builtins-constructor-gen.cc @@ -180,15 +180,14 @@ TNode ConstructorBuiltinsAssembler::EmitFastNewObject( SloppyTNode context, SloppyTNode target, SloppyTNode new_target, Label* call_runtime) { // Verify that the new target is a JSFunction. - Label fast(this), end(this); - GotoIf(HasInstanceType(new_target, JS_FUNCTION_TYPE), &fast); - Goto(call_runtime); - - BIND(&fast); + Label end(this); + TNode new_target_func = + HeapObjectToJSFunctionWithPrototypeSlot(new_target, call_runtime); + // Fast path. // Load the initial map and verify that it's in fact a map. TNode initial_map_or_proto = - LoadObjectField(new_target, JSFunction::kPrototypeOrInitialMapOffset); + LoadJSFunctionPrototypeOrInitialMap(new_target_func); GotoIf(TaggedIsSmi(initial_map_or_proto), call_runtime); GotoIf(DoesntHaveInstanceType(CAST(initial_map_or_proto), MAP_TYPE), call_runtime); diff --git a/src/builtins/cast.tq b/src/builtins/cast.tq index 770ed996b5..96526c2e4c 100644 --- a/src/builtins/cast.tq +++ b/src/builtins/cast.tq @@ -69,6 +69,9 @@ 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): @@ -420,6 +423,11 @@ Cast(o: HeapObject): Constructor return HeapObjectToConstructor(o) otherwise CastError; } +Cast(o: HeapObject): JSFunctionWithPrototypeSlot + labels CastError { + return HeapObjectToJSFunctionWithPrototypeSlot(o) otherwise CastError; +} + Cast(o: HeapObject): HeapNumber labels CastError { if (IsHeapNumber(o)) return %RawDownCast(o); diff --git a/src/codegen/code-stub-assembler.cc b/src/codegen/code-stub-assembler.cc index 4023a1c462..cb0e9d3a80 100644 --- a/src/codegen/code-stub-assembler.cc +++ b/src/codegen/code-stub-assembler.cc @@ -2741,42 +2741,38 @@ TNode CodeStubAssembler::IsGeneratorFunction( shared_function_info, SharedFunctionInfo::kFlagsOffset, MachineType::Uint32())); - return TNode::UncheckedCast(Word32Or( - Word32Or( - Word32Or( - Word32Equal(function_kind, - Int32Constant(FunctionKind::kAsyncGeneratorFunction)), - Word32Equal( - function_kind, - Int32Constant(FunctionKind::kAsyncConciseGeneratorMethod))), - Word32Equal(function_kind, - Int32Constant(FunctionKind::kGeneratorFunction))), - Word32Equal(function_kind, - Int32Constant(FunctionKind::kConciseGeneratorMethod)))); + // See IsGeneratorFunction(FunctionKind kind). + return IsInRange(function_kind, FunctionKind::kAsyncConciseGeneratorMethod, + FunctionKind::kConciseGeneratorMethod); } -TNode CodeStubAssembler::HasPrototypeSlot(TNode function) { - return TNode::UncheckedCast(IsSetWord32( - LoadMapBitField(LoadMap(function)))); +TNode CodeStubAssembler::IsJSFunctionWithPrototypeSlot( + TNode object) { + // Only JSFunction maps may have HasPrototypeSlotBit set. + return TNode::UncheckedCast( + IsSetWord32(LoadMapBitField(LoadMap(object)))); } -TNode CodeStubAssembler::HasPrototypeProperty(TNode function, - TNode map) { +void CodeStubAssembler::BranchIfHasPrototypeProperty( + TNode function, TNode function_map_bit_field, + Label* if_true, Label* if_false) { // (has_prototype_slot() && IsConstructor()) || // IsGeneratorFunction(shared()->kind()) uint32_t mask = Map::HasPrototypeSlotBit::kMask | Map::IsConstructorBit::kMask; - return TNode::UncheckedCast( - Word32Or(IsAllSetWord32(LoadMapBitField(map), mask), - IsGeneratorFunction(function))); + + GotoIf(IsAllSetWord32(function_map_bit_field, mask), if_true); + Branch(IsGeneratorFunction(function), if_true, if_false); } void CodeStubAssembler::GotoIfPrototypeRequiresRuntimeLookup( TNode function, TNode map, Label* runtime) { // !has_prototype_property() || has_non_instance_prototype() - GotoIfNot(HasPrototypeProperty(function, map), runtime); - GotoIf(IsSetWord32(LoadMapBitField(map)), - runtime); + TNode map_bit_field = LoadMapBitField(map); + Label next_check(this); + BranchIfHasPrototypeProperty(function, map_bit_field, &next_check, runtime); + BIND(&next_check); + GotoIf(IsSetWord32(map_bit_field), runtime); } TNode CodeStubAssembler::LoadJSFunctionPrototype( @@ -12955,14 +12951,6 @@ TNode CodeStubAssembler::IsElementsKindLessThanOrEqual( return Int32LessThanOrEqual(target_kind, Int32Constant(reference_kind)); } -TNode CodeStubAssembler::IsElementsKindInRange( - TNode target_kind, ElementsKind lower_reference_kind, - ElementsKind higher_reference_kind) { - return Uint32LessThanOrEqual( - Int32Sub(target_kind, Int32Constant(lower_reference_kind)), - Int32Constant(higher_reference_kind - lower_reference_kind)); -} - TNode CodeStubAssembler::IsDebugActive() { TNode is_debug_active = Load( ExternalConstant(ExternalReference::debug_is_active_address(isolate()))); diff --git a/src/codegen/code-stub-assembler.h b/src/codegen/code-stub-assembler.h index fe2eb1968b..19ae14bcbe 100644 --- a/src/codegen/code-stub-assembler.h +++ b/src/codegen/code-stub-assembler.h @@ -457,6 +457,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler return CAST(heap_object); } + TNode HeapObjectToJSFunctionWithPrototypeSlot( + TNode heap_object, Label* fail) { + GotoIfNot(IsJSFunctionWithPrototypeSlot(heap_object), fail); + return CAST(heap_object); + } + Node* MatchesParameterMode(Node* value, ParameterMode mode); #define PARAMETER_BINOP(OpName, IntPtrOpName, SmiOpName) \ @@ -932,6 +938,15 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode WordIsAligned(SloppyTNode word, size_t alignment); TNode WordIsPowerOfTwo(SloppyTNode value); + // Check if lower_limit <= value <= higher_limit. + template + TNode IsInRange(TNode value, U lower_limit, U higher_limit) { + DCHECK_LE(lower_limit, higher_limit); + STATIC_ASSERT(sizeof(U) <= kInt32Size); + return Uint32LessThanOrEqual(Int32Sub(value, Int32Constant(lower_limit)), + Int32Constant(higher_limit - lower_limit)); + } + #if DEBUG void Bind(Label* label, AssemblerDebugInfo debug_info); #endif // DEBUG @@ -1479,9 +1494,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode LoadJSArrayElementsMap(SloppyTNode kind, SloppyTNode native_context); - TNode HasPrototypeSlot(TNode function); + TNode IsJSFunctionWithPrototypeSlot(TNode object); TNode IsGeneratorFunction(TNode function); - TNode HasPrototypeProperty(TNode function, TNode map); + void BranchIfHasPrototypeProperty(TNode function, + TNode function_map_bit_field, + Label* if_true, Label* if_false); void GotoIfPrototypeRequiresRuntimeLookup(TNode function, TNode map, Label* runtime); // Load the "prototype" property of a JSFunction. @@ -2599,10 +2616,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ElementsKind reference_kind); TNode IsElementsKindLessThanOrEqual(TNode target_kind, ElementsKind reference_kind); - // Check if reference_kind_a <= target_kind <= reference_kind_b + // Check if lower_reference_kind <= target_kind <= higher_reference_kind. TNode IsElementsKindInRange(TNode target_kind, ElementsKind lower_reference_kind, - ElementsKind higher_reference_kind); + ElementsKind higher_reference_kind) { + return IsInRange(target_kind, lower_reference_kind, higher_reference_kind); + } // String helpers. // Load a character from a String (might flatten a ConsString). diff --git a/src/diagnostics/objects-debug.cc b/src/diagnostics/objects-debug.cc index a34cecbbf0..4e77c03daf 100644 --- a/src/diagnostics/objects-debug.cc +++ b/src/diagnostics/objects-debug.cc @@ -456,6 +456,9 @@ void Map::MapVerify(Isolate* isolate) { .IsConsistentWithBackPointers()); SLOW_DCHECK(!FLAG_unbox_double_fields || layout_descriptor().IsConsistentWithMap(*this)); + // Only JSFunction maps have has_prototype_slot() bit set and constructible + // JSFunction objects must have prototype slot. + CHECK_IMPLIES(has_prototype_slot(), instance_type() == JS_FUNCTION_TYPE); if (!may_have_interesting_symbols()) { CHECK(!has_named_interceptor()); CHECK(!is_dictionary_map()); diff --git a/src/objects/js-objects.tq b/src/objects/js-objects.tq index 7dcc8e16d9..b5e54f9277 100644 --- a/src/objects/js-objects.tq +++ b/src/objects/js-objects.tq @@ -70,15 +70,13 @@ extern class JSFunction extends JSFunctionOrBoundFunction { @noVerifier weak prototype_or_initial_map: JSReceiver|Map; } -extern macro HasPrototypeSlot(JSFunction): bool; +type JSFunctionWithPrototypeSlot extends JSFunction; macro GetDerivedMap(implicit context: Context)( target: JSFunction, newTarget: JSReceiver): Map { try { - const constructor = Cast(newTarget) otherwise SlowPath; - if (!HasPrototypeSlot(constructor)) { - goto SlowPath; - } + const constructor = + Cast(newTarget) otherwise SlowPath; assert(IsConstructor(constructor)); const map = Cast(constructor.prototype_or_initial_map) otherwise SlowPath;