Files
sdk/runtime/lib/object.cc
T
Régis Crelier db8b20107b Revert "Revert "Dart Core Lib change to support generic functions in class NoSuchMethodError.""
This reverts commit 8cf9ef22c4.

The expectations in Dart2js and Kernel tests have now been updated.

Change-Id: I9d65ff207490cfc783849b1b726db81cf56ecfc2
Reviewed-on: https://dart-review.googlesource.com/9124
Reviewed-by: Régis Crelier <regis@google.com>
2017-09-28 00:27:24 +00:00

395 lines
15 KiB
C++

// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/bootstrap_natives.h"
#include "lib/invocation_mirror.h"
#include "vm/code_patcher.h"
#include "vm/exceptions.h"
#include "vm/heap.h"
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/stack_frame.h"
#include "vm/symbols.h"
namespace dart {
DECLARE_FLAG(bool, trace_type_checks);
DEFINE_NATIVE_ENTRY(DartAsync_fatal, 1) {
// The dart:async library code entered an unrecoverable state.
const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
const char* msg = instance.ToCString();
OS::PrintErr("Fatal error in dart:async: %s\n", msg);
FATAL(msg);
return Object::null();
}
DEFINE_NATIVE_ENTRY(Object_equals, 1) {
// Implemented in the flow graph builder.
UNREACHABLE();
return Object::null();
}
DEFINE_NATIVE_ENTRY(Object_getHash, 1) {
// Please note that no handle is created for the argument.
// This is safe since the argument is only used in a tail call.
// The performance benefit is more than 5% when using hashCode.
#if defined(HASH_IN_OBJECT_HEADER)
return Smi::New(Object::GetCachedHash(arguments->NativeArgAt(0)));
#else
Heap* heap = isolate->heap();
ASSERT(arguments->NativeArgAt(0)->IsDartInstance());
return Smi::New(heap->GetHash(arguments->NativeArgAt(0)));
#endif
}
DEFINE_NATIVE_ENTRY(Object_setHash, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Smi, hash, arguments->NativeArgAt(1));
#if defined(HASH_IN_OBJECT_HEADER)
Object::SetCachedHash(arguments->NativeArgAt(0), hash.Value());
#else
const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
Heap* heap = isolate->heap();
heap->SetHash(instance.raw(), hash.Value());
#endif
return Object::null();
}
DEFINE_NATIVE_ENTRY(Object_toString, 1) {
const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
if (instance.IsString()) {
return instance.raw();
}
if (instance.IsAbstractType()) {
return AbstractType::Cast(instance).UserVisibleName();
}
const char* c_str = instance.ToCString();
return String::New(c_str);
}
DEFINE_NATIVE_ENTRY(Object_runtimeType, 1) {
const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
if (instance.IsString()) {
return Type::StringType();
} else if (instance.IsInteger()) {
return Type::IntType();
} else if (instance.IsDouble()) {
return Type::Double();
}
return instance.GetType(Heap::kNew);
}
DEFINE_NATIVE_ENTRY(Object_haveSameRuntimeType, 2) {
const Instance& left = Instance::CheckedHandle(arguments->NativeArgAt(0));
const Instance& right = Instance::CheckedHandle(arguments->NativeArgAt(1));
const intptr_t left_cid = left.GetClassId();
const intptr_t right_cid = right.GetClassId();
if (left_cid != right_cid) {
if (RawObject::IsIntegerClassId(left_cid)) {
return Bool::Get(RawObject::IsIntegerClassId(right_cid)).raw();
} else if (RawObject::IsStringClassId(right_cid)) {
return Bool::Get(RawObject::IsStringClassId(right_cid)).raw();
} else {
return Bool::False().raw();
}
}
const Class& cls = Class::Handle(left.clazz());
if (cls.IsClosureClass()) {
// TODO(vegorov): provide faster implementation for closure classes.
const AbstractType& left_type =
AbstractType::Handle(left.GetType(Heap::kNew));
const AbstractType& right_type =
AbstractType::Handle(right.GetType(Heap::kNew));
return Bool::Get(left_type.raw() == right_type.raw()).raw();
}
if (!cls.IsGeneric()) {
return Bool::True().raw();
}
const TypeArguments& left_type_arguments =
TypeArguments::Handle(left.GetTypeArguments());
const TypeArguments& right_type_arguments =
TypeArguments::Handle(right.GetTypeArguments());
return Bool::Get(left_type_arguments.Equals(right_type_arguments)).raw();
}
DEFINE_NATIVE_ENTRY(Object_instanceOf, 4) {
const Instance& instance =
Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
const TypeArguments& instantiator_type_arguments =
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(1));
const TypeArguments& function_type_arguments =
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(2));
const AbstractType& type =
AbstractType::CheckedHandle(zone, arguments->NativeArgAt(3));
ASSERT(type.IsFinalized());
ASSERT(!type.IsMalformed());
ASSERT(!type.IsMalbounded());
Error& bound_error = Error::Handle(zone, Error::null());
const bool is_instance_of = instance.IsInstanceOf(
type, instantiator_type_arguments, function_type_arguments, &bound_error);
if (FLAG_trace_type_checks) {
const char* result_str = is_instance_of ? "true" : "false";
OS::Print("Native Object.instanceOf: result %s\n", result_str);
const AbstractType& instance_type =
AbstractType::Handle(zone, instance.GetType(Heap::kNew));
OS::Print(" instance type: %s\n",
String::Handle(zone, instance_type.Name()).ToCString());
OS::Print(" test type: %s\n",
String::Handle(zone, type.Name()).ToCString());
if (!bound_error.IsNull()) {
OS::Print(" bound error: %s\n", bound_error.ToErrorCString());
}
}
if (!is_instance_of && !bound_error.IsNull()) {
// Throw a dynamic type error only if the instanceof test fails.
DartFrameIterator iterator(thread,
StackFrameIterator::kNoCrossThreadIteration);
StackFrame* caller_frame = iterator.NextFrame();
ASSERT(caller_frame != NULL);
const TokenPosition location = caller_frame->GetTokenPos();
String& bound_error_message =
String::Handle(zone, String::New(bound_error.ToErrorCString()));
Exceptions::CreateAndThrowTypeError(location, AbstractType::Handle(zone),
AbstractType::Handle(zone),
Symbols::Empty(), bound_error_message);
UNREACHABLE();
}
return Bool::Get(is_instance_of).raw();
}
DEFINE_NATIVE_ENTRY(Object_simpleInstanceOf, 2) {
// This native is only called when the right hand side passes
// SimpleInstanceOfType and it is a non-negative test.
const Instance& instance =
Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
const AbstractType& type =
AbstractType::CheckedHandle(zone, arguments->NativeArgAt(1));
ASSERT(type.IsFinalized());
ASSERT(!type.IsMalformed());
ASSERT(!type.IsMalbounded());
ASSERT(type.IsInstantiated());
Error& bound_error = Error::Handle(zone, Error::null());
const bool is_instance_of =
instance.IsInstanceOf(type, Object::null_type_arguments(),
Object::null_type_arguments(), &bound_error);
if (!is_instance_of && !bound_error.IsNull()) {
// Throw a dynamic type error only if the instanceof test fails.
DartFrameIterator iterator(thread,
StackFrameIterator::kNoCrossThreadIteration);
StackFrame* caller_frame = iterator.NextFrame();
ASSERT(caller_frame != NULL);
const TokenPosition location = caller_frame->GetTokenPos();
String& bound_error_message =
String::Handle(zone, String::New(bound_error.ToErrorCString()));
Exceptions::CreateAndThrowTypeError(location, AbstractType::Handle(zone),
AbstractType::Handle(zone),
Symbols::Empty(), bound_error_message);
UNREACHABLE();
}
return Bool::Get(is_instance_of).raw();
}
DEFINE_NATIVE_ENTRY(Object_as, 4) {
const Instance& instance =
Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
const TypeArguments& instantiator_type_arguments =
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(1));
const TypeArguments& function_type_arguments =
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(2));
AbstractType& type =
AbstractType::CheckedHandle(zone, arguments->NativeArgAt(3));
ASSERT(type.IsFinalized());
ASSERT(!type.IsMalformed());
ASSERT(!type.IsMalbounded());
Error& bound_error = Error::Handle(zone);
const bool is_instance_of =
instance.IsNull() ||
instance.IsInstanceOf(type, instantiator_type_arguments,
function_type_arguments, &bound_error);
if (FLAG_trace_type_checks) {
const char* result_str = is_instance_of ? "true" : "false";
OS::Print("Object.as: result %s\n", result_str);
const AbstractType& instance_type =
AbstractType::Handle(zone, instance.GetType(Heap::kNew));
OS::Print(" instance type: %s\n",
String::Handle(zone, instance_type.Name()).ToCString());
OS::Print(" cast type: %s\n",
String::Handle(zone, type.Name()).ToCString());
if (!bound_error.IsNull()) {
OS::Print(" bound error: %s\n", bound_error.ToErrorCString());
}
}
if (!is_instance_of) {
DartFrameIterator iterator(thread,
StackFrameIterator::kNoCrossThreadIteration);
StackFrame* caller_frame = iterator.NextFrame();
ASSERT(caller_frame != NULL);
const TokenPosition location = caller_frame->GetTokenPos();
const AbstractType& instance_type =
AbstractType::Handle(zone, instance.GetType(Heap::kNew));
if (!type.IsInstantiated()) {
// Instantiate type before reporting the error.
type = type.InstantiateFrom(instantiator_type_arguments,
function_type_arguments, NULL, NULL, NULL,
Heap::kNew);
// Note that the instantiated type may be malformed.
}
if (bound_error.IsNull()) {
Exceptions::CreateAndThrowTypeError(location, instance_type, type,
Symbols::InTypeCast(),
Object::null_string());
} else {
ASSERT(isolate->type_checks());
const String& bound_error_message =
String::Handle(zone, String::New(bound_error.ToErrorCString()));
Exceptions::CreateAndThrowTypeError(
location, instance_type, AbstractType::Handle(zone), Symbols::Empty(),
bound_error_message);
}
UNREACHABLE();
}
return instance.raw();
}
DEFINE_NATIVE_ENTRY(AbstractType_toString, 1) {
const AbstractType& type =
AbstractType::CheckedHandle(zone, arguments->NativeArgAt(0));
return type.UserVisibleName();
}
DEFINE_NATIVE_ENTRY(LibraryPrefix_invalidateDependentCode, 1) {
const LibraryPrefix& prefix =
LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
prefix.InvalidateDependentCode();
return Bool::Get(true).raw();
}
DEFINE_NATIVE_ENTRY(LibraryPrefix_load, 1) {
const LibraryPrefix& prefix =
LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
bool hasCompleted = prefix.LoadLibrary();
return Bool::Get(hasCompleted).raw();
}
DEFINE_NATIVE_ENTRY(LibraryPrefix_loadError, 1) {
const LibraryPrefix& prefix =
LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
// Currently all errors are Dart instances, e.g. I/O errors
// created by deferred loading code. LanguageErrors from
// failed loading or finalization attempts are propagated and result
// in the isolate's death.
const Instance& error = Instance::Handle(zone, prefix.LoadError());
return error.raw();
}
DEFINE_NATIVE_ENTRY(LibraryPrefix_isLoaded, 1) {
const LibraryPrefix& prefix =
LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
return Bool::Get(prefix.is_loaded()).raw();
}
DEFINE_NATIVE_ENTRY(Internal_inquireIs64Bit, 0) {
#if defined(ARCH_IS_64_BIT)
return Bool::True().raw();
#else
return Bool::False().raw();
#endif // defined(ARCH_IS_64_BIT)
}
DEFINE_NATIVE_ENTRY(Internal_prependTypeArguments, 3) {
const TypeArguments& function_type_arguments =
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0));
const TypeArguments& parent_type_arguments =
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(1));
if (function_type_arguments.IsNull() && parent_type_arguments.IsNull()) {
return TypeArguments::null();
}
GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_len, arguments->NativeArgAt(2));
const intptr_t len = smi_len.Value();
const TypeArguments& result =
TypeArguments::Handle(zone, TypeArguments::New(len, Heap::kNew));
AbstractType& type = AbstractType::Handle(zone);
const intptr_t split = parent_type_arguments.IsNull()
? len - function_type_arguments.Length()
: parent_type_arguments.Length();
for (intptr_t i = 0; i < split; i++) {
type = parent_type_arguments.IsNull() ? Type::DynamicType()
: parent_type_arguments.TypeAt(i);
result.SetTypeAt(i, type);
}
for (intptr_t i = split; i < len; i++) {
type = function_type_arguments.IsNull()
? Type::DynamicType()
: function_type_arguments.TypeAt(i - split);
result.SetTypeAt(i, type);
}
return result.Canonicalize();
}
DEFINE_NATIVE_ENTRY(InvocationMirror_unpackTypeArguments, 1) {
const TypeArguments& type_arguments =
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0));
const intptr_t len = type_arguments.Length();
ASSERT(len > 0);
const Array& type_list = Array::Handle(zone, Array::New(len));
TypeArguments& type_list_type_args =
TypeArguments::Handle(zone, TypeArguments::New(1));
type_list_type_args.SetTypeAt(0, Type::Handle(zone, Type::DartTypeType()));
type_list_type_args = type_list_type_args.Canonicalize();
type_list.SetTypeArguments(type_list_type_args);
AbstractType& type = AbstractType::Handle(zone);
for (intptr_t i = 0; i < len; i++) {
type = type_arguments.TypeAt(i);
type_list.SetAt(i, type);
}
type_list.MakeImmutable();
return type_list.raw();
}
DEFINE_NATIVE_ENTRY(NoSuchMethodError_existingMethodSignature, 3) {
const Instance& receiver = Instance::CheckedHandle(arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(String, method_name, arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(Smi, invocation_type, arguments->NativeArgAt(2));
InvocationMirror::Level level;
InvocationMirror::Kind kind;
InvocationMirror::DecodeType(invocation_type.Value(), &level, &kind);
Function& function = Function::Handle();
if (receiver.IsType()) {
Class& cls = Class::Handle(Type::Cast(receiver).type_class());
if (level == InvocationMirror::kConstructor) {
function = cls.LookupConstructor(method_name);
if (function.IsNull()) {
function = cls.LookupFactory(method_name);
}
} else {
function = cls.LookupStaticFunction(method_name);
}
} else if (receiver.IsClosure()) {
function = Closure::Cast(receiver).function();
} else {
Class& cls = Class::Handle(receiver.clazz());
if (level != InvocationMirror::kSuper) {
function = cls.LookupDynamicFunction(method_name);
}
while (function.IsNull()) {
cls = cls.SuperClass();
if (cls.IsNull()) break;
function = cls.LookupDynamicFunction(method_name);
}
}
if (!function.IsNull()) {
return function.UserVisibleSignature();
}
return String::null();
}
} // namespace dart