@@ -1752,14 +1752,13 @@ void FlowGraphBuilder::BuildArgumentTypeChecks(
1752
1752
}
1753
1753
1754
1754
BlockEntryInstr* FlowGraphBuilder::BuildPrologue (BlockEntryInstr* normal_entry,
1755
- PrologueInfo* prologue_info,
1756
- JoinEntryInstr* nsm) {
1755
+ PrologueInfo* prologue_info) {
1757
1756
const bool compiling_for_osr = IsCompiledForOsr ();
1758
1757
1759
1758
kernel::PrologueBuilder prologue_builder (
1760
1759
parsed_function_, last_used_block_id_, compiling_for_osr, IsInlining ());
1761
1760
BlockEntryInstr* instruction_cursor =
1762
- prologue_builder.BuildPrologue (normal_entry, prologue_info, nsm );
1761
+ prologue_builder.BuildPrologue (normal_entry, prologue_info);
1763
1762
1764
1763
last_used_block_id_ = prologue_builder.last_used_block_id ();
1765
1764
@@ -1835,6 +1834,7 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher(
1835
1834
const Function& function) {
1836
1835
// This function is specialized for a receiver class, a method name, and
1837
1836
// the arguments descriptor at a call site.
1837
+ const ArgumentsDescriptor descriptor (saved_args_desc_array ());
1838
1838
1839
1839
graph_entry_ =
1840
1840
new (Z) GraphEntryInstr (*parsed_function_, Compiler::kNoOSRDeoptId );
@@ -1846,18 +1846,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher(
1846
1846
BlockEntryInstr* instruction_cursor =
1847
1847
BuildPrologue (normal_entry, &prologue_info);
1848
1848
1849
- // The backend will expect an array of default values for all the named
1850
- // parameters, even if they are all known to be passed at the call site
1851
- // because the call site matches the arguments descriptor. Use null for
1852
- // the default values.
1853
- ArgumentsDescriptor descriptor (saved_args_desc_array ());
1854
- ZoneGrowableArray<const Instance*>* default_values =
1855
- new ZoneGrowableArray<const Instance*>(Z, descriptor.NamedCount ());
1856
- for (intptr_t i = 0 ; i < descriptor.NamedCount (); ++i) {
1857
- default_values->Add (&Object::null_instance ());
1858
- }
1859
- parsed_function_->set_default_parameter_values (default_values);
1860
-
1861
1849
Fragment body (instruction_cursor);
1862
1850
body += CheckStackOverflowInPrologue (function.token_pos ());
1863
1851
@@ -2153,10 +2141,38 @@ Fragment FlowGraphBuilder::BuildClosureCallArgumentsValidCheck(
2153
2141
ASSERT (has_saved_args_desc_array ());
2154
2142
const ArgumentsDescriptor descriptor (saved_args_desc_array ());
2155
2143
2156
- // Type argument length checking, including checking for delayed type
2157
- // arguments, is already done in the prologue builder.
2144
+ LocalVariable* temp = parsed_function_->expression_temp_var ();
2158
2145
2159
2146
Fragment check_entry;
2147
+ // We only need to check the length of any explicitly provided type arguments.
2148
+ if (descriptor.TypeArgsLen () > 0 ) {
2149
+ Fragment check_type_args_length;
2150
+ check_type_args_length += LoadLocal (closure);
2151
+ check_type_args_length += LoadNativeField (Slot::Closure_function ());
2152
+ check_type_args_length += LoadNativeField (Slot::Function_type_parameters ());
2153
+ check_type_args_length += StoreLocal (TokenPosition::kNoSource , temp);
2154
+ TargetEntryInstr *null, *not_null;
2155
+ check_type_args_length += BranchIfNull (&null, ¬_null);
2156
+ check_type_args_length.current = not_null; // Continue in non-error case.
2157
+
2158
+ // The function is not generic.
2159
+ Fragment (null) + Goto (nsm);
2160
+
2161
+ check_type_args_length += LoadLocal (temp);
2162
+ check_type_args_length += LoadNativeField (Slot::TypeArguments_length ());
2163
+ check_type_args_length += IntConstant (descriptor.TypeArgsLen ());
2164
+ TargetEntryInstr *equal, *not_equal;
2165
+ check_type_args_length += BranchIfEqual (&equal, ¬_equal);
2166
+ check_type_args_length.current = equal; // Continue in non-error case.
2167
+
2168
+ Fragment (not_equal) + Goto (nsm);
2169
+
2170
+ // Type arguments should not be provided if there are delayed type
2171
+ // arguments, as then the closure itself is not generic.
2172
+ check_entry += TestDelayedTypeArgs (closure, /* present=*/ Goto (nsm),
2173
+ /* absent=*/ check_type_args_length);
2174
+ }
2175
+
2160
2176
check_entry += LoadLocal (vars->has_named_params );
2161
2177
TargetEntryInstr *has_named, *has_positional;
2162
2178
check_entry += BranchIfTrue (&has_named, &has_positional);
@@ -2280,6 +2296,7 @@ Fragment FlowGraphBuilder::BuildClosureCallNamedArgumentCheck(
2280
2296
2281
2297
FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher (
2282
2298
const Function& function) {
2299
+ const ArgumentsDescriptor descriptor (saved_args_desc_array ());
2283
2300
// Find the name of the field we should dispatch to.
2284
2301
const Class& owner = Class::Handle (Z, function.Owner ());
2285
2302
ASSERT (!owner.IsNull ());
@@ -2302,36 +2319,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher(
2302
2319
const bool is_closure_call = (owner.raw () == closure_class.raw ()) &&
2303
2320
field_name.Equals (Symbols::Call ());
2304
2321
2305
- JoinEntryInstr* nsm = nullptr ;
2306
- if (is_dynamic_call && is_closure_call) {
2307
- // Create a NSM block that can be shared with the prologue builder.
2308
- nsm = BuildThrowNoSuchMethod ();
2309
- // The whole reason for making this invoke field dispatcher is that
2310
- // this closure call needs checking, so we shouldn't inline a call to an
2311
- // unchecked entry that can't tail call NSM.
2312
- InlineBailout (
2313
- " kernel::FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher" );
2314
- }
2315
-
2316
- // Set default parameters & construct argument names array.
2317
- //
2318
- // The backend will expect an array of default values for all the named
2319
- // parameters, even if they are all known to be passed at the call site
2320
- // because the call site matches the arguments descriptor. Use null for
2321
- // the default values.
2322
- const ArgumentsDescriptor descriptor (saved_args_desc_array ());
2323
- const Array& argument_names =
2324
- Array::ZoneHandle (Z, Array::New (descriptor.NamedCount (), Heap::kOld ));
2325
- ZoneGrowableArray<const Instance*>* default_values =
2326
- new ZoneGrowableArray<const Instance*>(Z, descriptor.NamedCount ());
2327
- String& string_handle = String::Handle (Z);
2328
- for (intptr_t i = 0 ; i < descriptor.NamedCount (); ++i) {
2329
- default_values->Add (&Object::null_instance ());
2330
- string_handle = descriptor.NameAt (i);
2331
- argument_names.SetAt (i, string_handle);
2332
- }
2333
- parsed_function_->set_default_parameter_values (default_values);
2334
-
2335
2322
graph_entry_ =
2336
2323
new (Z) GraphEntryInstr (*parsed_function_, Compiler::kNoOSRDeoptId );
2337
2324
@@ -2340,29 +2327,27 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher(
2340
2327
2341
2328
PrologueInfo prologue_info (-1 , -1 );
2342
2329
BlockEntryInstr* instruction_cursor =
2343
- BuildPrologue (normal_entry, &prologue_info, nsm );
2330
+ BuildPrologue (normal_entry, &prologue_info);
2344
2331
2345
2332
Fragment body (instruction_cursor);
2346
2333
body += CheckStackOverflowInPrologue (function.token_pos ());
2347
2334
2348
- if (descriptor.TypeArgsLen () > 0 ) {
2349
- LocalVariable* type_args = parsed_function_->function_type_arguments ();
2350
- ASSERT (type_args != NULL );
2351
- body += LoadLocal (type_args);
2352
- }
2353
-
2335
+ // Build any dynamic closure call checks before pushing arguments to the
2336
+ // final call on the stack to make debugging easier.
2354
2337
LocalVariable* closure = NULL ;
2355
2338
if (is_closure_call) {
2356
2339
closure = parsed_function_->ParameterVariable (0 );
2357
-
2358
- // The closure itself is the first argument.
2359
- body += LoadLocal (closure);
2360
-
2361
2340
if (is_dynamic_call) {
2362
- // We should have a throw NSM block from the prologue.
2363
- ASSERT (nsm != nullptr );
2341
+ // The whole reason for making this invoke field dispatcher is that
2342
+ // this closure call needs checking, so we shouldn't inline a call to an
2343
+ // unchecked entry that can't tail call NSM.
2344
+ InlineBailout (
2345
+ " kernel::FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher" );
2346
+
2364
2347
// Init the variables we'll be using for dynamic call checking.
2365
2348
body += BuildDynamicCallVarsInit (closure);
2349
+
2350
+ JoinEntryInstr* nsm = BuildThrowNoSuchMethod ();
2366
2351
// Check that the shape of the arguments generally matches what the
2367
2352
// closure function expects. The only remaining non-type check after this
2368
2353
// is that the names for optional arguments are valid.
@@ -2372,7 +2357,29 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher(
2372
2357
// in the closure body to here, using the dynamic versions of
2373
2358
// AssertSubtype to typecheck the type arguments using the runtime types
2374
2359
// available in the closure object.
2360
+
2361
+ // TODO(dartbug.com/40813): Move checks that are currently compiled
2362
+ // in the closure body to here, using the dynamic versions of
2363
+ // AssertAssignable to typecheck the parameters using the runtime types
2364
+ // available in the closure object.
2365
+ //
2366
+ // For now, we check that any named arguments have valid names.
2367
+ for (intptr_t pos = descriptor.PositionalCount ();
2368
+ pos < descriptor.Count (); pos++) {
2369
+ body += BuildClosureCallNamedArgumentCheck (closure, pos, nsm);
2370
+ }
2375
2371
}
2372
+ }
2373
+
2374
+ if (descriptor.TypeArgsLen () > 0 ) {
2375
+ LocalVariable* type_args = parsed_function_->function_type_arguments ();
2376
+ ASSERT (type_args != nullptr );
2377
+ body += LoadLocal (type_args);
2378
+ }
2379
+
2380
+ if (is_closure_call) {
2381
+ // The closure itself is the first argument.
2382
+ body += LoadLocal (closure);
2376
2383
} else {
2377
2384
// Invoke the getter to get the field value.
2378
2385
body += LoadLocal (parsed_function_->ParameterVariable (0 ));
@@ -2383,18 +2390,21 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher(
2383
2390
}
2384
2391
2385
2392
// Push all arguments onto the stack.
2386
- intptr_t pos = 1 ;
2387
- for (; pos < descriptor.Count (); pos++) {
2393
+ for (intptr_t pos = 1 ; pos < descriptor.Count (); pos++) {
2388
2394
body += LoadLocal (parsed_function_->ParameterVariable (pos));
2389
- if (is_closure_call && is_dynamic_call) {
2390
- // TODO(dartbug.com/40813): Move checks that are currently compiled
2391
- // in the closure body to here, using the dynamic versions of
2392
- // AssertAssignable to typecheck the parameters using the runtime types
2393
- // available in the closure object.
2394
- //
2395
- // For now, we check that any named arguments have valid names.
2396
- body += BuildClosureCallNamedArgumentCheck (closure, pos, nsm);
2395
+ }
2396
+
2397
+ // Construct argument names array if necessary.
2398
+ const Array* argument_names = &Object::null_array ();
2399
+ if (descriptor.NamedCount () > 0 ) {
2400
+ const auto & array_handle =
2401
+ Array::ZoneHandle (Z, Array::New (descriptor.NamedCount (), Heap::kNew ));
2402
+ String& string_handle = String::Handle (Z);
2403
+ for (intptr_t i = 0 ; i < descriptor.NamedCount (); ++i) {
2404
+ string_handle = descriptor.NameAt (i);
2405
+ array_handle.SetAt (i, string_handle);
2397
2406
}
2407
+ argument_names = &array_handle;
2398
2408
}
2399
2409
2400
2410
if (is_closure_call) {
@@ -2403,14 +2413,14 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher(
2403
2413
body += LoadNativeField (Slot::Closure_function ());
2404
2414
2405
2415
body += ClosureCall (TokenPosition::kNoSource , descriptor.TypeArgsLen (),
2406
- descriptor.Count (), argument_names);
2416
+ descriptor.Count (), * argument_names);
2407
2417
} else {
2408
2418
const intptr_t kNumArgsChecked = 1 ;
2409
2419
body +=
2410
2420
InstanceCall (TokenPosition::kMinSource ,
2411
2421
is_dynamic_call ? Symbols::DynamicCall () : Symbols::Call (),
2412
2422
Token::kILLEGAL , descriptor.TypeArgsLen (),
2413
- descriptor.Count (), argument_names, kNumArgsChecked );
2423
+ descriptor.Count (), * argument_names, kNumArgsChecked );
2414
2424
}
2415
2425
2416
2426
body += Return (TokenPosition::kNoSource );
0 commit comments