diff --git a/runtime/lib/internal_patch.dart b/runtime/lib/internal_patch.dart index b9fb751be81..dc6b038b243 100644 --- a/runtime/lib/internal_patch.dart +++ b/runtime/lib/internal_patch.dart @@ -25,13 +25,8 @@ List makeFixedListUnmodifiable(List fixedLengthList) native "Internal_makeFixedListUnmodifiable"; @patch -Object extractTypeArguments(T instance, Function extract) { - // TODO(31371): Implement this correctly for Dart 2.0. - // In Dart 1.0, instantiating the generic with dynamic (which this does), - // gives you an object that can be used anywhere a more specific type is - // expected, so this works for now. - return extract(); -} +Object extractTypeArguments(T instance, Function extract) + native "Internal_extractTypeArguments"; class VMLibraryHooks { // Example: "dart:isolate _Timer._factory" diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc index 7b830791194..5f3e4496968 100644 --- a/runtime/lib/object.cc +++ b/runtime/lib/object.cc @@ -311,6 +311,144 @@ DEFINE_NATIVE_ENTRY(Internal_inquireIs64Bit, 0) { #endif // defined(ARCH_IS_64_BIT) } +static bool ExtractInterfaceTypeArgs(Zone* zone, + const Class& instance_cls, + const TypeArguments& instance_type_args, + const Class& interface_cls, + TypeArguments* interface_type_args) { + Class& cur_cls = Class::Handle(zone, instance_cls.raw()); + // The following code is a specialization of Class::TypeTestNonRecursive(). + Array& interfaces = Array::Handle(zone); + AbstractType& interface = AbstractType::Handle(zone); + Class& cur_interface_cls = Class::Handle(zone); + TypeArguments& cur_interface_type_args = TypeArguments::Handle(zone); + Error& error = Error::Handle(zone); + while (true) { + // Additional subtyping rules related to 'FutureOr' are not applied. + if (cur_cls.raw() == interface_cls.raw()) { + *interface_type_args = instance_type_args.raw(); + return true; + } + interfaces = cur_cls.interfaces(); + for (intptr_t i = 0; i < interfaces.Length(); i++) { + interface ^= interfaces.At(i); + ASSERT(interface.IsFinalized() && !interface.IsMalbounded()); + cur_interface_cls = interface.type_class(); + cur_interface_type_args = interface.arguments(); + if (!cur_interface_type_args.IsNull() && + !cur_interface_type_args.IsInstantiated()) { + error = Error::null(); + cur_interface_type_args = cur_interface_type_args.InstantiateFrom( + instance_type_args, Object::null_type_arguments(), kNoneFree, + &error, NULL, NULL, Heap::kNew); + if (!error.IsNull()) { + continue; // Another interface may work better. + } + } + if (ExtractInterfaceTypeArgs(zone, cur_interface_cls, + cur_interface_type_args, interface_cls, + interface_type_args)) { + return true; + } + } + cur_cls = cur_cls.SuperClass(); + if (cur_cls.IsNull()) { + return false; + } + } +} + +DEFINE_NATIVE_ENTRY(Internal_extractTypeArguments, 2) { + const Instance& instance = + Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); + const Instance& extract = + Instance::CheckedHandle(zone, arguments->NativeArgAt(1)); + + Class& interface_cls = Class::Handle(zone); + intptr_t num_type_args = 0; // Remains 0 when executing Dart 1.0 code. + // TODO(regis): Check for strong mode too? + if (Isolate::Current()->reify_generic_functions()) { + const TypeArguments& function_type_args = + TypeArguments::Handle(zone, arguments->NativeTypeArgs()); + if (function_type_args.Length() == 1) { + const AbstractType& function_type_arg = + AbstractType::Handle(zone, function_type_args.TypeAt(0)); + if (function_type_arg.IsType() && + (function_type_arg.arguments() == TypeArguments::null())) { + interface_cls = function_type_arg.type_class(); + num_type_args = interface_cls.NumTypeParameters(); + } + } + if (num_type_args == 0) { + Exceptions::ThrowArgumentError(String::Handle( + zone, + String::New( + "single function type argument must specify a generic class"))); + } + } + if (instance.IsNull()) { + Exceptions::ThrowArgumentError(instance); + } + // Function 'extract' must be generic and accept the same number of type args, + // unless we execute Dart 1.0 code. + if (extract.IsNull() || !extract.IsClosure() || + ((num_type_args > 0) && // Dart 1.0 if num_type_args == 0. + (Function::Handle(zone, Closure::Cast(extract).function()) + .NumTypeParameters() != num_type_args))) { + Exceptions::ThrowArgumentError(String::Handle( + zone, + String::New("argument 'extract' is not a generic function or not one " + "accepting the correct number of type arguments"))); + } + TypeArguments& extracted_type_args = TypeArguments::Handle(zone); + if (num_type_args > 0) { + // The passed instance must implement interface_cls. + TypeArguments& interface_type_args = TypeArguments::Handle(zone); + interface_type_args = TypeArguments::New(num_type_args); + Class& instance_cls = Class::Handle(zone, instance.clazz()); + TypeArguments& instance_type_args = TypeArguments::Handle(zone); + if (instance_cls.NumTypeArguments() > 0) { + instance_type_args = instance.GetTypeArguments(); + } + if (!ExtractInterfaceTypeArgs(zone, instance_cls, instance_type_args, + interface_cls, &interface_type_args)) { + Exceptions::ThrowArgumentError(String::Handle( + zone, String::New("type of argument 'instance' is not a subtype of " + "the function type argument"))); + } + if (!interface_type_args.IsNull()) { + extracted_type_args = TypeArguments::New(num_type_args); + const intptr_t offset = interface_cls.NumTypeArguments() - num_type_args; + AbstractType& type_arg = AbstractType::Handle(zone); + for (intptr_t i = 0; i < num_type_args; i++) { + type_arg = interface_type_args.TypeAt(offset + i); + extracted_type_args.SetTypeAt(i, type_arg); + } + extracted_type_args = extracted_type_args.Canonicalize(); // Can be null. + } + } + // Call the closure 'extract'. + Array& args_desc = Array::Handle(zone); + Array& args = Array::Handle(zone); + if (extracted_type_args.IsNull()) { + args_desc = ArgumentsDescriptor::New(0, 1); + args = Array::New(1); + args.SetAt(0, extract); + } else { + args_desc = ArgumentsDescriptor::New(num_type_args, 1); + args = Array::New(2); + args.SetAt(0, extracted_type_args); + args.SetAt(1, extract); + } + const Object& result = + Object::Handle(zone, DartEntry::InvokeClosure(args, args_desc)); + if (result.IsError()) { + Exceptions::PropagateError(Error::Cast(result)); + UNREACHABLE(); + } + return result.raw(); +} + DEFINE_NATIVE_ENTRY(Internal_prependTypeArguments, 3) { const TypeArguments& function_type_arguments = TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)); diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h index 2bc5b481617..f3eeafe5ba2 100644 --- a/runtime/vm/bootstrap_natives.h +++ b/runtime/vm/bootstrap_natives.h @@ -314,6 +314,7 @@ namespace dart { V(Internal_makeListFixedLength, 1) \ V(Internal_makeFixedListUnmodifiable, 1) \ V(Internal_inquireIs64Bit, 0) \ + V(Internal_extractTypeArguments, 2) \ V(Internal_prependTypeArguments, 3) \ V(InvocationMirror_decodePositionalCountEntry, 1) \ V(InvocationMirror_decodeTypeArgsLenEntry, 1) \ diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc index 09a191597f0..3f4833839da 100644 --- a/runtime/vm/compiler/backend/il_arm.cc +++ b/runtime/vm/compiler/backend/il_arm.cc @@ -880,7 +880,11 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { const Register result = locs()->out(0).reg(); // All arguments are already @SP due to preceding PushArgument()s. - ASSERT(ArgumentCount() == function().NumParameters()); + ASSERT(ArgumentCount() == function().NumParameters() + + (function().IsGeneric() && + Isolate::Current()->reify_generic_functions()) + ? 1 + : 0); // Push the result place holder initialized to NULL. __ PushObject(Object::null_object()); diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc index fa52fc873eb..2826114642b 100644 --- a/runtime/vm/compiler/backend/il_arm64.cc +++ b/runtime/vm/compiler/backend/il_arm64.cc @@ -769,7 +769,11 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { const Register result = locs()->out(0).reg(); // All arguments are already @SP due to preceding PushArgument()s. - ASSERT(ArgumentCount() == function().NumParameters()); + ASSERT(ArgumentCount() == function().NumParameters() + + (function().IsGeneric() && + Isolate::Current()->reify_generic_functions()) + ? 1 + : 0); // Push the result place holder initialized to NULL. __ PushObject(Object::null_object()); diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc index cb564555369..da721b8e358 100644 --- a/runtime/vm/compiler/backend/il_ia32.cc +++ b/runtime/vm/compiler/backend/il_ia32.cc @@ -818,7 +818,11 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function()); // All arguments are already @ESP due to preceding PushArgument()s. - ASSERT(ArgumentCount() == function().NumParameters()); + ASSERT(ArgumentCount() == function().NumParameters() + + (function().IsGeneric() && + Isolate::Current()->reify_generic_functions()) + ? 1 + : 0); // Push the result place holder initialized to NULL. __ PushObject(Object::null_object()); diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc index 5fcdd8e9f5a..31bf62112f8 100644 --- a/runtime/vm/compiler/backend/il_x64.cc +++ b/runtime/vm/compiler/backend/il_x64.cc @@ -784,7 +784,11 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function()); // All arguments are already @RSP due to preceding PushArgument()s. - ASSERT(ArgumentCount() == function().NumParameters()); + ASSERT(ArgumentCount() == function().NumParameters() + + (function().IsGeneric() && + Isolate::Current()->reify_generic_functions()) + ? 1 + : 0); // Push the result place holder initialized to NULL. __ PushObject(Object::null_object()); diff --git a/runtime/vm/compiler/frontend/flow_graph_builder.cc b/runtime/vm/compiler/frontend/flow_graph_builder.cc index 0b92e55b6e3..1e12eda4d30 100644 --- a/runtime/vm/compiler/frontend/flow_graph_builder.cc +++ b/runtime/vm/compiler/frontend/flow_graph_builder.cc @@ -3318,15 +3318,24 @@ void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) { const ParsedFunction& pf = owner_->parsed_function(); const String& name = String::ZoneHandle(Z, function.native_name()); - ZoneGrowableArray& args = - *new (Z) ZoneGrowableArray(function.NumParameters()); + const intptr_t num_params = function.NumParameters(); + ZoneGrowableArray* args = NULL; + if (function.IsGeneric() && owner()->isolate()->reify_generic_functions()) { + args = new (Z) ZoneGrowableArray(1 + num_params); + LocalVariable* type_args = pf.RawTypeArgumentsVariable(); + ASSERT(type_args != NULL); + Value* value = Bind(new (Z) LoadLocalInstr(*type_args, node->token_pos())); + args->Add(PushArgument(value)); + } else { + args = new (Z) ZoneGrowableArray(num_params); + } for (intptr_t i = 0; i < function.NumParameters(); ++i) { LocalVariable* parameter = pf.RawParameterVariable(i); Value* value = Bind(new (Z) LoadLocalInstr(*parameter, node->token_pos())); - args.Add(PushArgument(value)); + args->Add(PushArgument(value)); } NativeCallInstr* native_call = new (Z) NativeCallInstr( - &name, &function, FLAG_link_natives_lazily, node->token_pos(), &args); + &name, &function, FLAG_link_natives_lazily, node->token_pos(), args); ReturnDefinition(native_call); } diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc index 9e776f90e5f..a46453b23fc 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.cc +++ b/runtime/vm/compiler/frontend/kernel_to_il.cc @@ -1397,7 +1397,12 @@ Fragment BaseFlowGraphBuilder::NullConstant() { Fragment FlowGraphBuilder::NativeCall(const String* name, const Function* function) { InlineBailout("kernel::FlowGraphBuilder::NativeCall"); - ArgumentArray arguments = GetArguments(function->NumParameters()); + const intptr_t num_args = + function->NumParameters() + + ((function->IsGeneric() && Isolate::Current()->reify_generic_functions()) + ? 1 + : 0); + ArgumentArray arguments = GetArguments(num_args); NativeCallInstr* call = new (Z) NativeCallInstr(name, function, FLAG_link_natives_lazily, TokenPosition::kNoSource, arguments); @@ -2015,6 +2020,11 @@ Fragment FlowGraphBuilder::NativeFunctionBody(intptr_t first_positional_offset, break; default: { String& name = String::ZoneHandle(Z, function.native_name()); + if (function.IsGeneric() && + Isolate::Current()->reify_generic_functions()) { + body += LoadLocal(parsed_function_->RawTypeArgumentsVariable()); + body += PushArgument(); + } for (intptr_t i = 0; i < function.NumParameters(); ++i) { body += LoadLocal(parsed_function_->RawParameterVariable(i)); body += PushArgument(); diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc index 5fab765d1ef..6129213e7e9 100644 --- a/runtime/vm/dart_entry.cc +++ b/runtime/vm/dart_entry.cc @@ -112,11 +112,6 @@ RawObject* DartEntry::InvokeFunction(const Function& function, Zone* zone = thread->zone(); ASSERT(thread->IsMutatorThread()); ScopedIsolateStackLimits stack_limit(thread, current_sp); - if (ArgumentsDescriptor(arguments_descriptor).TypeArgsLen() > 0) { - const String& message = String::Handle(String::New( - "Unsupported invocation of Dart generic function with type arguments")); - return ApiError::New(message); - } if (!function.HasCode()) { const Object& result = Object::Handle(zone, Compiler::CompileFunction(thread, function)); diff --git a/runtime/vm/native_arguments.h b/runtime/vm/native_arguments.h index a083201f01d..f7151e3133f 100644 --- a/runtime/vm/native_arguments.h +++ b/runtime/vm/native_arguments.h @@ -77,8 +77,11 @@ void VerifyOnTransition(); // following signature: // void function_name(NativeArguments arguments); // Inside the function, arguments are accessed as follows: -// const Instance& arg0 = Instance::CheckedHandle(arguments.ArgAt(0)); -// const Smi& arg1 = Smi::CheckedHandle(arguments.ArgAt(1)); +// const Instance& arg0 = Instance::CheckedHandle(arguments.NativeArgAt(0)); +// const Smi& arg1 = Smi::CheckedHandle(arguments.NativeArgAt(1)); +// If the function is generic, type arguments are accessed as follows: +// const TypeArguments& type_args = +// TypeArguments::Handle(arguments.NativeTypeArgs()); // The return value is set as follows: // arguments.SetReturn(result); // NOTE: Since we pass 'this' as a pass-by-value argument in the stubs we don't @@ -87,6 +90,8 @@ void VerifyOnTransition(); class NativeArguments { public: Thread* thread() const { return thread_; } + + // Includes type arguments vector. int ArgCount() const { return ArgcBits::decode(argc_tag_); } RawObject* ArgAt(int index) const { @@ -103,6 +108,7 @@ class NativeArguments { return *arg_ptr; } + // Does not include hidden type arguments vector. int NativeArgCount() const { int function_bits = FunctionBits::decode(argc_tag_); return ArgCount() - NumHiddenArgs(function_bits); @@ -110,9 +116,11 @@ class NativeArguments { RawObject* NativeArg0() const { int function_bits = FunctionBits::decode(argc_tag_); - if (function_bits == (kClosureFunctionBit | kInstanceFunctionBit)) { + if ((function_bits & (kClosureFunctionBit | kInstanceFunctionBit)) == + (kClosureFunctionBit | kInstanceFunctionBit)) { // Retrieve the receiver from the context. - const Object& closure = Object::Handle(ArgAt(0)); + const int closure_index = (function_bits & kGenericFunctionBit) ? 1 : 0; + const Object& closure = Object::Handle(ArgAt(closure_index)); const Context& context = Context::Handle(Closure::Cast(closure).context()); return context.At(0); @@ -130,6 +138,11 @@ class NativeArguments { return ArgAt(actual_index); } + RawTypeArguments* NativeTypeArgs() { + ASSERT(ToGenericFunction()); + return TypeArguments::RawCast(ArgAt(0)); + } + void SetReturn(const Object& value) const { *retval_ = value.raw(); } RawObject* ReturnValue() const { @@ -166,7 +179,7 @@ class NativeArguments { static int ComputeArgcTag(const Function& function) { ASSERT(function.is_native()); ASSERT(!function.IsGenerativeConstructor()); // Not supported. - int tag = ArgcBits::encode(function.NumParameters()); + int argc = function.NumParameters(); int function_bits = 0; if (!function.is_static()) { function_bits |= kInstanceFunctionBit; @@ -174,6 +187,11 @@ class NativeArguments { if (function.IsClosureFunction()) { function_bits |= kClosureFunctionBit; } + if (function.IsGeneric() && Isolate::Current()->reify_generic_functions()) { + function_bits |= kGenericFunctionBit; + argc++; + } + int tag = ArgcBits::encode(argc); tag = FunctionBits::update(function_bits, tag); return tag; } @@ -182,12 +200,13 @@ class NativeArguments { enum { kInstanceFunctionBit = 1, kClosureFunctionBit = 2, + kGenericFunctionBit = 4, }; enum ArgcTagBits { kArgcBit = 0, kArgcSize = 24, kFunctionBit = 24, - kFunctionSize = 2, + kFunctionSize = 3, }; class ArgcBits : public BitField {}; class FunctionBits @@ -221,15 +240,24 @@ class NativeArguments { return (FunctionBits::decode(argc_tag_) & kClosureFunctionBit); } + // Returns true if the arguments are those of a generic function call. + bool ToGenericFunction() const { + return (FunctionBits::decode(argc_tag_) & kGenericFunctionBit); + } + int NumHiddenArgs(int function_bits) const { + int num_hidden_args = 0; // For static closure functions, the closure at index 0 is hidden. // In the instance closure function case, the receiver is accessed from // the context and the closure at index 0 is hidden, so the apparent // argument count remains unchanged. - if (function_bits == kClosureFunctionBit) { - return 1; + if ((function_bits & kClosureFunctionBit) == kClosureFunctionBit) { + num_hidden_args++; } - return 0; + if ((function_bits & kGenericFunctionBit) == kGenericFunctionBit) { + num_hidden_args++; + } + return num_hidden_args; } Thread* thread_; // Current thread pointer. diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc index 6776065d214..f0015587341 100644 --- a/runtime/vm/simulator_dbc.cc +++ b/runtime/vm/simulator_dbc.cc @@ -1324,7 +1324,6 @@ RawObject* Simulator::Call(const Code& code, // Load argument descriptor. argdesc_ = arguments_descriptor.raw(); - ASSERT(ArgumentsDescriptor(arguments_descriptor).TypeArgsLen() == 0); // Ready to start executing bytecode. Load entry point and corresponding // object pool. diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc index 4ded3092581..9b9ca0b20b2 100644 --- a/runtime/vm/stub_code_arm.cc +++ b/runtime/vm/stub_code_arm.cc @@ -822,9 +822,11 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { // Load arguments descriptor array into R4, which is passed to Dart code. __ ldr(R4, Address(R1, VMHandles::kOffsetOfRawPtrInHandle)); - // No need to check for type args, disallowed by DartEntry::InvokeFunction. - // Load number of arguments into R9. + // Load number of arguments into R9 and adjust count for type arguments. + __ ldr(R3, FieldAddress(R4, ArgumentsDescriptor::type_args_len_offset())); __ ldr(R9, FieldAddress(R4, ArgumentsDescriptor::count_offset())); + __ cmp(R3, Operand(0)); + __ AddImmediate(R9, R9, Smi::RawValue(1), NE); // Include the type arguments. __ SmiUntag(R9); // Compute address of 'arguments array' data area into R2. diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc index a071130e20a..e23bb907609 100644 --- a/runtime/vm/stub_code_arm64.cc +++ b/runtime/vm/stub_code_arm64.cc @@ -868,9 +868,12 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { // Load arguments descriptor array into R4, which is passed to Dart code. __ LoadFromOffset(R4, R1, VMHandles::kOffsetOfRawPtrInHandle); - // No need to check for type args, disallowed by DartEntry::InvokeFunction. - // Load number of arguments into S5. + // Load number of arguments into R5 and adjust count for type arguments. __ LoadFieldFromOffset(R5, R4, ArgumentsDescriptor::count_offset()); + __ LoadFieldFromOffset(R3, R4, ArgumentsDescriptor::type_args_len_offset()); + __ AddImmediate(TMP, R5, 1); // Include the type arguments. + __ cmp(R3, Operand(0)); + __ csinc(R5, R5, TMP, EQ); // R5 <- (R3 == 0) ? R5 : TMP + 1 (R5 : R5 + 2). __ SmiUntag(R5); // Compute address of 'arguments array' data area into R2. diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc index 2707fc7cc4c..9ef1116db87 100644 --- a/runtime/vm/stub_code_ia32.cc +++ b/runtime/vm/stub_code_ia32.cc @@ -739,9 +739,16 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { __ movl(EDX, Address(EBP, kArgumentsDescOffset)); __ movl(EDX, Address(EDX, VMHandles::kOffsetOfRawPtrInHandle)); - // No need to check for type args, disallowed by DartEntry::InvokeFunction. - // Load number of arguments into EBX. + // Load number of arguments into EBX and adjust count for type arguments. __ movl(EBX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); + __ cmpl(FieldAddress(EDX, ArgumentsDescriptor::type_args_len_offset()), + Immediate(0)); + Label args_count_ok; + __ j(EQUAL, &args_count_ok, Assembler::kNearJump); + __ addl(EBX, Immediate(Smi::RawValue(1))); // Include the type arguments. + __ Bind(&args_count_ok); + // Save number of arguments as Smi on stack, replacing ArgumentsDesc. + __ movl(Address(EBP, kArgumentsDescOffset), EBX); __ SmiUntag(EBX); // Set up arguments for the dart call. @@ -769,11 +776,8 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { __ movl(EAX, Address(EAX, VMHandles::kOffsetOfRawPtrInHandle)); __ call(FieldAddress(EAX, Code::entry_point_offset())); - // Reread the arguments descriptor array to obtain the number of passed - // arguments. + // Read the saved number of passed arguments as Smi. __ movl(EDX, Address(EBP, kArgumentsDescOffset)); - __ movl(EDX, Address(EDX, VMHandles::kOffsetOfRawPtrInHandle)); - __ movl(EDX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); // Get rid of arguments pushed on the stack. __ leal(ESP, Address(ESP, EDX, TIMES_2, 0)); // EDX is a Smi. diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc index 0363b27574b..1fcf009bb9d 100644 --- a/runtime/vm/stub_code_x64.cc +++ b/runtime/vm/stub_code_x64.cc @@ -756,7 +756,7 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { // | saved PC (return to DartEntry::InvokeFunction) | const intptr_t kInitialOffset = 2; - // Save arguments descriptor array. + // Save arguments descriptor array, later replaced by Smi argument count. const intptr_t kArgumentsDescOffset = -(kInitialOffset)*kWordSize; __ pushq(kArgDescReg); @@ -807,9 +807,16 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { // Push arguments. At this point we only need to preserve kTargetCodeReg. ASSERT(kTargetCodeReg != RDX); - // No need to check for type args, disallowed by DartEntry::InvokeFunction. - // Load number of arguments into RBX. + // Load number of arguments into RBX and adjust count for type arguments. __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); + __ cmpq(FieldAddress(R10, ArgumentsDescriptor::type_args_len_offset()), + Immediate(0)); + Label args_count_ok; + __ j(EQUAL, &args_count_ok, Assembler::kNearJump); + __ addq(RBX, Immediate(Smi::RawValue(1))); // Include the type arguments. + __ Bind(&args_count_ok); + // Save number of arguments as Smi on stack, replacing saved ArgumentsDesc. + __ movq(Address(RBP, kArgumentsDescOffset), RBX); __ SmiUntag(RBX); // Compute address of 'arguments array' data area into RDX. @@ -835,11 +842,9 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { __ movq(kTargetCodeReg, FieldAddress(CODE_REG, Code::entry_point_offset())); __ call(kTargetCodeReg); // R10 is the arguments descriptor array. - // Read the saved arguments descriptor array to obtain the number of passed - // arguments. - __ movq(kArgDescReg, Address(RBP, kArgumentsDescOffset)); - __ movq(R10, Address(kArgDescReg, VMHandles::kOffsetOfRawPtrInHandle)); - __ movq(RDX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); + // Read the saved number of passed arguments as Smi. + __ movq(RDX, Address(RBP, kArgumentsDescOffset)); + // Get rid of arguments pushed on the stack. __ leaq(RSP, Address(RSP, RDX, TIMES_4, 0)); // RDX is a Smi. diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status index fee2233480a..75f9b08ddd8 100644 --- a/tests/language_2/language_2_kernel.status +++ b/tests/language_2/language_2_kernel.status @@ -414,7 +414,6 @@ example_constructor_test: Fail, OK external_test/10: MissingRuntimeError # KernelVM bug: Unbound external. external_test/13: MissingRuntimeError # KernelVM bug: Unbound external. external_test/20: MissingRuntimeError # KernelVM bug: Unbound external. -extract_type_arguments_test: RuntimeError # Issue 31371 f_bounded_quantification_test/01: MissingCompileTimeError f_bounded_quantification_test/02: MissingCompileTimeError factory2_test/03: MissingCompileTimeError @@ -1239,7 +1238,6 @@ external_test/10: MissingRuntimeError # KernelVM bug: Unbound external. external_test/13: MissingRuntimeError # KernelVM bug: Unbound external. external_test/20: MissingRuntimeError # KernelVM bug: Unbound external. external_test/24: Pass, CompileTimeError # Started to pass after switching to batch-mode. -extract_type_arguments_test: RuntimeError # Issue 31371 f_bounded_quantification_test/01: MissingCompileTimeError f_bounded_quantification_test/02: MissingCompileTimeError factory2_test/03: MissingCompileTimeError diff --git a/tests/language_2/language_2_precompiled.status b/tests/language_2/language_2_precompiled.status index eb3d6b7b51f..6bedfa3911d 100644 --- a/tests/language_2/language_2_precompiled.status +++ b/tests/language_2/language_2_precompiled.status @@ -282,7 +282,6 @@ export_ambiguous_main_negative_test: Fail # Issue 14763 export_ambiguous_main_negative_test: Skip # Issue 29895 export_ambiguous_main_test: Crash export_double_same_main_test: Skip # Issue 29895 -extract_type_arguments_test: RuntimeError # Issue 31371 f_bounded_quantification_test/01: MissingCompileTimeError f_bounded_quantification_test/02: MissingCompileTimeError factory1_test/00: MissingCompileTimeError diff --git a/tests/language_2/language_2_vm.status b/tests/language_2/language_2_vm.status index a81c743e7a9..54520a6aa7f 100644 --- a/tests/language_2/language_2_vm.status +++ b/tests/language_2/language_2_vm.status @@ -310,7 +310,6 @@ empty_block_case_test: MissingCompileTimeError enum_private_test/02: MissingCompileTimeError error_stacktrace_test/00: MissingCompileTimeError export_ambiguous_main_test: MissingCompileTimeError -extract_type_arguments_test: RuntimeError # Issue 31371 f_bounded_quantification_test/01: MissingCompileTimeError f_bounded_quantification_test/02: MissingCompileTimeError factory1_test/00: MissingCompileTimeError