[VM runtime] Implement support for _extractTypeArguments in the VM (fixes #31805).
Update status files. This cl includes implementing these two features on all platforms: 1) Support calling generic functions via DartEntry::InvokeFunction(). 2) Support native generic functions. These are currently allowed, but type arguments are ignored, and therefore not accessible from the C++ side. Change-Id: Id39e8ca46c2ba1ba3d46946c16712a8572ff64ea Reviewed-on: https://dart-review.googlesource.com/34023 Commit-Queue: Régis Crelier <regis@google.com> Reviewed-by: Siva Annamalai <asiva@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
d539c78af1
commit
0c2793b3db
@@ -25,13 +25,8 @@ List<T> makeFixedListUnmodifiable<T>(List<T> fixedLengthList)
|
||||
native "Internal_makeFixedListUnmodifiable";
|
||||
|
||||
@patch
|
||||
Object extractTypeArguments<T>(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>(T instance, Function extract)
|
||||
native "Internal_extractTypeArguments";
|
||||
|
||||
class VMLibraryHooks {
|
||||
// Example: "dart:isolate _Timer._factory"
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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<PushArgumentInstr*>& args =
|
||||
*new (Z) ZoneGrowableArray<PushArgumentInstr*>(function.NumParameters());
|
||||
const intptr_t num_params = function.NumParameters();
|
||||
ZoneGrowableArray<PushArgumentInstr*>* args = NULL;
|
||||
if (function.IsGeneric() && owner()->isolate()->reify_generic_functions()) {
|
||||
args = new (Z) ZoneGrowableArray<PushArgumentInstr*>(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<PushArgumentInstr*>(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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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<intptr_t, int32_t, kArgcBit, kArgcSize> {};
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user