mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 12:30:03 +00:00
[vm/interpreter] Support closures in bytecode.
Support reordered bytecode metadata sections. For now, read but ignore exceptions table in bytecode metadata. Change-Id: I86202acc8ea22d746deaa894afd685d2f1daaaf8 Reviewed-on: https://dart-review.googlesource.com/56036 Commit-Queue: Régis Crelier <regis@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
e1cabfd1d4
commit
63ff7ee922
|
@ -914,8 +914,7 @@ InferredTypeMetadata InferredTypeMetadataHelper::GetInferredType(
|
|||
}
|
||||
|
||||
#if defined(DART_USE_INTERPRETER)
|
||||
void BytecodeMetadataHelper::CopyBytecode(const Function& function) {
|
||||
// TODO(regis): Avoid copying bytecode from mapped kernel binary.
|
||||
void BytecodeMetadataHelper::ReadMetadata(const Function& function) {
|
||||
const intptr_t node_offset = function.kernel_offset();
|
||||
const intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
|
||||
if (md_offset < 0) {
|
||||
|
@ -925,14 +924,51 @@ void BytecodeMetadataHelper::CopyBytecode(const Function& function) {
|
|||
AlternativeReadingScope alt(&builder_->reader_, &H.metadata_payloads(),
|
||||
md_offset);
|
||||
|
||||
// Read bytecode.
|
||||
intptr_t bytecode_size = builder_->reader_.ReadUInt();
|
||||
intptr_t bytecode_offset = builder_->reader_.offset();
|
||||
uint8_t* bytecode_data = builder_->reader_.CopyDataIntoZone(
|
||||
builder_->zone_, bytecode_offset, bytecode_size);
|
||||
// Create object pool and read pool entries.
|
||||
const intptr_t obj_count = builder_->reader_.ReadListLength();
|
||||
const ObjectPool& pool =
|
||||
ObjectPool::Handle(builder_->zone_, ObjectPool::New(obj_count));
|
||||
ReadPoolEntries(function, function, pool, 0);
|
||||
|
||||
// This enum and the code below reading the constant pool from kernel must be
|
||||
// kept in sync with pkg/vm/lib/bytecode/constant_pool.dart.
|
||||
// Read bytecode and attach to function.
|
||||
const Code& bytecode = Code::Handle(builder_->zone_, ReadBytecode(pool));
|
||||
function.AttachBytecode(bytecode);
|
||||
|
||||
// Read exceptions table.
|
||||
ReadExceptionsTable(bytecode);
|
||||
|
||||
if (FLAG_dump_kernel_bytecode) {
|
||||
KernelBytecodeDisassembler::Disassemble(function);
|
||||
}
|
||||
|
||||
// Read closures.
|
||||
Function& closure = Function::Handle(builder_->zone_);
|
||||
Code& closure_bytecode = Code::Handle(builder_->zone_);
|
||||
intptr_t num_closures = builder_->ReadListLength();
|
||||
for (intptr_t i = 0; i < num_closures; i++) {
|
||||
intptr_t closure_index = builder_->ReadUInt();
|
||||
ASSERT(closure_index < obj_count);
|
||||
closure ^= pool.ObjectAt(closure_index);
|
||||
|
||||
// Read closure bytecode and attach to closure function.
|
||||
closure_bytecode = ReadBytecode(pool);
|
||||
closure.AttachBytecode(closure_bytecode);
|
||||
|
||||
// Read closure exceptions table.
|
||||
ReadExceptionsTable(closure_bytecode);
|
||||
|
||||
if (FLAG_dump_kernel_bytecode) {
|
||||
KernelBytecodeDisassembler::Disassemble(closure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t BytecodeMetadataHelper::ReadPoolEntries(const Function& function,
|
||||
const Function& inner_function,
|
||||
const ObjectPool& pool,
|
||||
intptr_t from_index) {
|
||||
// These enums and the code below reading the constant pool from kernel must
|
||||
// be kept in sync with pkg/vm/lib/bytecode/constant_pool.dart.
|
||||
enum ConstantPoolTag {
|
||||
kInvalid,
|
||||
kNull,
|
||||
|
@ -954,19 +990,25 @@ void BytecodeMetadataHelper::CopyBytecode(const Function& function) {
|
|||
kInstance,
|
||||
kSymbol,
|
||||
kTypeArgumentsForInstanceAllocation,
|
||||
kContextOffset,
|
||||
kClosureFunction,
|
||||
kEndClosureFunctionScope,
|
||||
};
|
||||
|
||||
enum InvocationKind {
|
||||
method, // x.foo(...) or foo(...)
|
||||
getter, // x.foo
|
||||
setter // x.foo = ...
|
||||
};
|
||||
|
||||
// Read object pool.
|
||||
builder_->reader_.set_offset(bytecode_offset + bytecode_size);
|
||||
intptr_t obj_count = builder_->reader_.ReadListLength();
|
||||
const ObjectPool& obj_pool =
|
||||
ObjectPool::Handle(builder_->zone_, ObjectPool::New(obj_count));
|
||||
Object& obj = Object::Handle(builder_->zone_);
|
||||
Object& elem = Object::Handle(builder_->zone_);
|
||||
Array& array = Array::Handle(builder_->zone_);
|
||||
Field& field = Field::Handle(builder_->zone_);
|
||||
Class& cls = Class::Handle(builder_->zone_);
|
||||
String& name = String::Handle(builder_->zone_);
|
||||
for (intptr_t i = 0; i < obj_count; ++i) {
|
||||
const intptr_t obj_count = pool.Length();
|
||||
for (intptr_t i = from_index; i < obj_count; ++i) {
|
||||
const intptr_t tag = builder_->ReadTag();
|
||||
switch (tag) {
|
||||
case ConstantPoolTag::kInvalid:
|
||||
|
@ -1018,7 +1060,7 @@ void BytecodeMetadataHelper::CopyBytecode(const Function& function) {
|
|||
name = H.DartSymbolPlain(target).raw();
|
||||
intptr_t arg_desc_index = builder_->ReadUInt();
|
||||
ASSERT(arg_desc_index < i);
|
||||
array ^= obj_pool.ObjectAt(arg_desc_index);
|
||||
array ^= pool.ObjectAt(arg_desc_index);
|
||||
// TODO(regis): Should num_args_tested be explicitly provided?
|
||||
obj = ICData::New(function, name,
|
||||
array, // Arguments descriptor.
|
||||
|
@ -1029,18 +1071,34 @@ void BytecodeMetadataHelper::CopyBytecode(const Function& function) {
|
|||
#endif
|
||||
} break;
|
||||
case ConstantPoolTag::kStaticICData: {
|
||||
InvocationKind kind = static_cast<InvocationKind>(builder_->ReadByte());
|
||||
NameIndex target = builder_->ReadCanonicalNameReference();
|
||||
if (H.IsConstructor(target)) {
|
||||
name = H.DartConstructorName(target).raw();
|
||||
elem = H.LookupConstructorByKernelConstructor(target);
|
||||
} else if (H.IsField(target)) {
|
||||
if (kind == InvocationKind::getter) {
|
||||
name = H.DartGetterName(target).raw();
|
||||
} else if (kind == InvocationKind::setter) {
|
||||
name = H.DartSetterName(target).raw();
|
||||
} else {
|
||||
ASSERT(kind == InvocationKind::method);
|
||||
UNIMPLEMENTED(); // TODO(regis): Revisit.
|
||||
}
|
||||
field = H.LookupFieldByKernelField(target);
|
||||
cls = field.Owner();
|
||||
elem = cls.LookupStaticFunction(name);
|
||||
} else {
|
||||
if ((kind == InvocationKind::method) && H.IsGetter(target)) {
|
||||
UNIMPLEMENTED(); // TODO(regis): Revisit.
|
||||
}
|
||||
name = H.DartProcedureName(target).raw();
|
||||
elem = H.LookupStaticMethodByKernelProcedure(target);
|
||||
}
|
||||
ASSERT(elem.IsFunction());
|
||||
intptr_t arg_desc_index = builder_->ReadUInt();
|
||||
ASSERT(arg_desc_index < i);
|
||||
array ^= obj_pool.ObjectAt(arg_desc_index);
|
||||
array ^= pool.ObjectAt(arg_desc_index);
|
||||
obj = ICData::New(function, name,
|
||||
array, // Arguments descriptor.
|
||||
Thread::kNoDeoptId, 0 /* num_args_tested */,
|
||||
|
@ -1067,11 +1125,9 @@ void BytecodeMetadataHelper::CopyBytecode(const Function& function) {
|
|||
ASSERT(obj.IsClass());
|
||||
break;
|
||||
case ConstantPoolTag::kTypeArgumentsFieldOffset:
|
||||
obj =
|
||||
cls =
|
||||
H.LookupClassByKernelClass(builder_->ReadCanonicalNameReference());
|
||||
ASSERT(obj.IsClass());
|
||||
obj = Smi::New(Class::Cast(obj).type_arguments_field_offset() /
|
||||
kWordSize);
|
||||
obj = Smi::New(cls.type_arguments_field_offset() / kWordSize);
|
||||
break;
|
||||
case ConstantPoolTag::kTearOff:
|
||||
obj = H.LookupStaticMethodByKernelProcedure(
|
||||
|
@ -1101,20 +1157,19 @@ void BytecodeMetadataHelper::CopyBytecode(const Function& function) {
|
|||
for (intptr_t j = 0; j < length; j++) {
|
||||
intptr_t elem_index = builder_->ReadUInt();
|
||||
ASSERT(elem_index < i);
|
||||
elem = obj_pool.ObjectAt(elem_index);
|
||||
elem = pool.ObjectAt(elem_index);
|
||||
array.SetAt(j, elem);
|
||||
}
|
||||
obj = H.Canonicalize(Array::Cast(obj));
|
||||
ASSERT(!obj.IsNull());
|
||||
} break;
|
||||
case ConstantPoolTag::kInstance: {
|
||||
obj =
|
||||
cls =
|
||||
H.LookupClassByKernelClass(builder_->ReadCanonicalNameReference());
|
||||
ASSERT(obj.IsClass());
|
||||
obj = Instance::New(Class::Cast(obj), Heap::kOld);
|
||||
obj = Instance::New(cls, Heap::kOld);
|
||||
intptr_t elem_index = builder_->ReadUInt();
|
||||
ASSERT(elem_index < i);
|
||||
elem = obj_pool.ObjectAt(elem_index);
|
||||
elem = pool.ObjectAt(elem_index);
|
||||
if (!elem.IsNull()) {
|
||||
ASSERT(elem.IsTypeArguments());
|
||||
Instance::Cast(obj).SetTypeArguments(TypeArguments::Cast(elem));
|
||||
|
@ -1126,7 +1181,7 @@ void BytecodeMetadataHelper::CopyBytecode(const Function& function) {
|
|||
field = H.LookupFieldByKernelField(field_name);
|
||||
intptr_t elem_index = builder_->ReadUInt();
|
||||
ASSERT(elem_index < i);
|
||||
elem = obj_pool.ObjectAt(elem_index);
|
||||
elem = pool.ObjectAt(elem_index);
|
||||
Instance::Cast(obj).SetField(field, elem);
|
||||
}
|
||||
obj = H.Canonicalize(Instance::Cast(obj));
|
||||
|
@ -1136,34 +1191,193 @@ void BytecodeMetadataHelper::CopyBytecode(const Function& function) {
|
|||
ASSERT(String::Cast(obj).IsSymbol());
|
||||
break;
|
||||
case kTypeArgumentsForInstanceAllocation: {
|
||||
obj =
|
||||
cls =
|
||||
H.LookupClassByKernelClass(builder_->ReadCanonicalNameReference());
|
||||
ASSERT(obj.IsClass());
|
||||
intptr_t elem_index = builder_->ReadUInt();
|
||||
ASSERT(elem_index < i);
|
||||
elem = obj_pool.ObjectAt(elem_index);
|
||||
elem = pool.ObjectAt(elem_index);
|
||||
ASSERT(elem.IsNull() || elem.IsTypeArguments());
|
||||
elem = Type::New(Class::Cast(obj), TypeArguments::Cast(elem),
|
||||
TokenPosition::kNoSource);
|
||||
elem = ClassFinalizer::FinalizeType(Class::Cast(obj), Type::Cast(elem));
|
||||
elem =
|
||||
Type::New(cls, TypeArguments::Cast(elem), TokenPosition::kNoSource);
|
||||
elem = ClassFinalizer::FinalizeType(cls, Type::Cast(elem));
|
||||
obj = Type::Cast(elem).arguments();
|
||||
} break;
|
||||
case ConstantPoolTag::kContextOffset: {
|
||||
intptr_t index = builder_->ReadUInt();
|
||||
if (i == 0) {
|
||||
obj = Smi::New(Context::parent_offset() / kWordSize);
|
||||
} else {
|
||||
obj = Smi::New(Context::variable_offset(index - 1) / kWordSize);
|
||||
}
|
||||
} break;
|
||||
case ConstantPoolTag::kClosureFunction: {
|
||||
name = H.DartSymbolPlain(builder_->ReadStringReference()).raw();
|
||||
const Function& closure = Function::Handle(
|
||||
builder_->zone_,
|
||||
Function::NewClosureFunction(name, inner_function,
|
||||
TokenPosition::kNoSource));
|
||||
|
||||
FunctionNodeHelper function_node_helper(builder_);
|
||||
function_node_helper.ReadUntilExcluding(
|
||||
FunctionNodeHelper::kTypeParameters);
|
||||
builder_->LoadAndSetupTypeParameters(builder_->active_class(), closure,
|
||||
builder_->ReadListLength(),
|
||||
closure);
|
||||
function_node_helper.SetJustRead(FunctionNodeHelper::kTypeParameters);
|
||||
|
||||
// Scope remains opened until ConstantPoolTag::kEndClosureFunctionScope.
|
||||
ActiveTypeParametersScope scope(
|
||||
builder_->active_class(), &closure,
|
||||
TypeArguments::Handle(builder_->zone_, closure.type_parameters()),
|
||||
builder_->zone_);
|
||||
|
||||
function_node_helper.ReadUntilExcluding(
|
||||
FunctionNodeHelper::kPositionalParameters);
|
||||
|
||||
intptr_t required_parameter_count =
|
||||
function_node_helper.required_parameter_count_;
|
||||
intptr_t total_parameter_count =
|
||||
function_node_helper.total_parameter_count_;
|
||||
|
||||
intptr_t positional_parameter_count = builder_->ReadListLength();
|
||||
|
||||
intptr_t named_parameter_count =
|
||||
total_parameter_count - positional_parameter_count;
|
||||
|
||||
const intptr_t extra_parameters = 1;
|
||||
closure.set_num_fixed_parameters(extra_parameters +
|
||||
required_parameter_count);
|
||||
if (named_parameter_count > 0) {
|
||||
closure.SetNumOptionalParameters(named_parameter_count, false);
|
||||
} else {
|
||||
closure.SetNumOptionalParameters(
|
||||
positional_parameter_count - required_parameter_count, true);
|
||||
}
|
||||
intptr_t parameter_count = extra_parameters + total_parameter_count;
|
||||
closure.set_parameter_types(Array::Handle(
|
||||
builder_->zone_, Array::New(parameter_count, Heap::kOld)));
|
||||
closure.set_parameter_names(Array::Handle(
|
||||
builder_->zone_, Array::New(parameter_count, Heap::kOld)));
|
||||
|
||||
intptr_t pos = 0;
|
||||
closure.SetParameterTypeAt(pos, AbstractType::dynamic_type());
|
||||
closure.SetParameterNameAt(pos, Symbols::ClosureParameter());
|
||||
pos++;
|
||||
|
||||
for (intptr_t j = 0; j < positional_parameter_count; ++j, ++pos) {
|
||||
VariableDeclarationHelper helper(builder_);
|
||||
helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
|
||||
const AbstractType& type =
|
||||
builder_->type_translator_.BuildVariableType();
|
||||
Tag tag = builder_->ReadTag(); // read (first part of) initializer.
|
||||
if (tag == kSomething) {
|
||||
builder_->SkipExpression(); // read (actual) initializer.
|
||||
}
|
||||
|
||||
closure.SetParameterTypeAt(pos, type);
|
||||
closure.SetParameterNameAt(pos,
|
||||
H.DartSymbolObfuscate(helper.name_index_));
|
||||
}
|
||||
|
||||
intptr_t named_parameter_count_check = builder_->ReadListLength();
|
||||
ASSERT(named_parameter_count_check == named_parameter_count);
|
||||
for (intptr_t j = 0; j < named_parameter_count; ++j, ++pos) {
|
||||
VariableDeclarationHelper helper(builder_);
|
||||
helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
|
||||
const AbstractType& type =
|
||||
builder_->type_translator_.BuildVariableType();
|
||||
Tag tag = builder_->ReadTag(); // read (first part of) initializer.
|
||||
if (tag == kSomething) {
|
||||
builder_->SkipExpression(); // read (actual) initializer.
|
||||
}
|
||||
|
||||
closure.SetParameterTypeAt(pos, type);
|
||||
closure.SetParameterNameAt(pos,
|
||||
H.DartSymbolObfuscate(helper.name_index_));
|
||||
}
|
||||
|
||||
function_node_helper.SetJustRead(FunctionNodeHelper::kNamedParameters);
|
||||
|
||||
const AbstractType& return_type =
|
||||
builder_->type_translator_.BuildVariableType();
|
||||
closure.set_result_type(return_type);
|
||||
function_node_helper.SetJustRead(FunctionNodeHelper::kReturnType);
|
||||
// The closure has no body.
|
||||
function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd);
|
||||
|
||||
pool.SetTypeAt(i, ObjectPool::kTaggedObject);
|
||||
pool.SetObjectAt(i, closure);
|
||||
|
||||
// Continue reading the constant pool entries inside the opened
|
||||
// ActiveTypeParametersScope until the scope gets closed by a
|
||||
// kEndClosureFunctionScope tag, in which case control returns here.
|
||||
i = ReadPoolEntries(function, closure, pool, i + 1);
|
||||
// Pool entry at index i has been set to null, because it was a
|
||||
// kEndClosureFunctionScope.
|
||||
ASSERT(pool.ObjectAt(i) == Object::null());
|
||||
continue;
|
||||
}
|
||||
case ConstantPoolTag::kEndClosureFunctionScope: {
|
||||
// Entry is not used and set to null.
|
||||
obj = Object::null();
|
||||
pool.SetTypeAt(i, ObjectPool::kTaggedObject);
|
||||
pool.SetObjectAt(i, obj);
|
||||
return i; // The caller will close the scope.
|
||||
} break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
obj_pool.SetTypeAt(i, ObjectPool::kTaggedObject);
|
||||
obj_pool.SetObjectAt(i, obj);
|
||||
pool.SetTypeAt(i, ObjectPool::kTaggedObject);
|
||||
pool.SetObjectAt(i, obj);
|
||||
}
|
||||
// Return the index of the last read pool entry.
|
||||
return obj_count - 1;
|
||||
}
|
||||
|
||||
const Code& bytecode = Code::Handle(
|
||||
builder_->zone_,
|
||||
Code::FinalizeBytecode(reinterpret_cast<void*>(bytecode_data),
|
||||
bytecode_size, obj_pool));
|
||||
function.AttachBytecode(bytecode);
|
||||
RawCode* BytecodeMetadataHelper::ReadBytecode(const ObjectPool& pool) {
|
||||
// TODO(regis): Avoid copying bytecode from mapped kernel binary.
|
||||
intptr_t size = builder_->reader_.ReadUInt();
|
||||
intptr_t offset = builder_->reader_.offset();
|
||||
uint8_t* data =
|
||||
builder_->reader_.CopyDataIntoZone(builder_->zone_, offset, size);
|
||||
builder_->reader_.set_offset(offset + size);
|
||||
|
||||
if (FLAG_dump_kernel_bytecode) {
|
||||
KernelBytecodeDisassembler::Disassemble(function);
|
||||
// Create and return code object.
|
||||
return Code::FinalizeBytecode(reinterpret_cast<void*>(data), size, pool);
|
||||
}
|
||||
|
||||
void BytecodeMetadataHelper::ReadExceptionsTable(const Code& bytecode) {
|
||||
const ObjectPool& pool =
|
||||
ObjectPool::Handle(builder_->zone_, bytecode.object_pool());
|
||||
AbstractType& handled_type = AbstractType::Handle(builder_->zone_);
|
||||
|
||||
// Encoding of ExceptionsTable is described in
|
||||
// pkg/vm/lib/bytecode/exceptions.dart.
|
||||
intptr_t try_block_count = builder_->reader_.ReadListLength();
|
||||
for (intptr_t i = 0; i < try_block_count; i++) {
|
||||
intptr_t outer_try_index_plus1 = builder_->reader_.ReadUInt();
|
||||
intptr_t outer_try_index = outer_try_index_plus1 - 1;
|
||||
USE(outer_try_index);
|
||||
intptr_t start_pc = builder_->reader_.ReadUInt();
|
||||
USE(start_pc);
|
||||
intptr_t end_pc = builder_->reader_.ReadUInt();
|
||||
USE(end_pc);
|
||||
intptr_t handler_pc = builder_->reader_.ReadUInt();
|
||||
USE(handler_pc);
|
||||
uint8_t flags = builder_->reader_.ReadByte();
|
||||
// flagNeedsStackTrace = 1 << 0;
|
||||
// flagIsSynthetic = 1 << 1;
|
||||
USE(flags);
|
||||
|
||||
intptr_t type_count = builder_->reader_.ReadListLength();
|
||||
for (intptr_t j = 0; j < type_count; j++) {
|
||||
intptr_t type_index = builder_->reader_.ReadUInt();
|
||||
ASSERT(type_index < pool.Length());
|
||||
handled_type ^= pool.ObjectAt(type_index);
|
||||
}
|
||||
}
|
||||
// TODO(regis): Generate exception handlers (as well as pc descriptors)
|
||||
// and store in bytecode: bytecode.set_exception_handlers(exception_handlers);
|
||||
}
|
||||
#endif // defined(DART_USE_INTERPRETER)
|
||||
|
||||
|
@ -6171,7 +6385,7 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraph(intptr_t kernel_offset) {
|
|||
// TODO(regis): Clean up this logic of when to compile.
|
||||
// If the bytecode was previously loaded, we really want to compile.
|
||||
if (!function.HasBytecode()) {
|
||||
bytecode_metadata_helper_.CopyBytecode(function);
|
||||
bytecode_metadata_helper_.ReadMetadata(function);
|
||||
if (function.HasBytecode()) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -670,7 +670,16 @@ class BytecodeMetadataHelper : public MetadataHelper {
|
|||
: MetadataHelper(builder) {}
|
||||
|
||||
#if defined(DART_USE_INTERPRETER)
|
||||
void CopyBytecode(const Function& function);
|
||||
void ReadMetadata(const Function& function);
|
||||
|
||||
private:
|
||||
// Returns the index of the last read pool entry.
|
||||
intptr_t ReadPoolEntries(const Function& function,
|
||||
const Function& inner_function,
|
||||
const ObjectPool& pool,
|
||||
intptr_t from_index);
|
||||
RawCode* ReadBytecode(const ObjectPool& pool);
|
||||
void ReadExceptionsTable(const Code& bytecode);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue