24a30defcc
When handling hot reload via library tag handler's Kernel tag VM must guarantee that external typed data it receives from the embedder stays alive for as long as VM has any structures referencing this kernel binary. This is achieved by attaching original typed data to KernelProgramInfo objects containing the views into it. Unfortunately kernel::Reader APIs were somewhat unsafe: allowing to construct reader object from Program's raw buffer and forget to set the link betwen the reader and original typed data. This created a situation where reloading using a multicomponent Kernel binary would result in KernelProgramInfo objects without link to the original typed data, which in turn leads to premature finalization of external typed data and subsequent crashes when trying to use delete kernel binary. This CL reworks kernel::Reader API (by introducing kernel::ProgramBinary wrapper) to make it safer and make sure that connection is preserved. TEST=vm/cc/IsolateReload_RegressB179030011 Bug: b/179030011 Change-Id: I05f8c31c3cb8e67de6e94a20d9501a5f476b7e27 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/182280 Commit-Queue: Vyacheslav Egorov <vegorov@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com>
257 lines
8.2 KiB
C++
257 lines
8.2 KiB
C++
// Copyright (c) 2016, 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.
|
|
|
|
#ifndef RUNTIME_VM_KERNEL_H_
|
|
#define RUNTIME_VM_KERNEL_H_
|
|
|
|
#include <memory>
|
|
|
|
#include "platform/assert.h"
|
|
#include "vm/allocation.h"
|
|
#include "vm/globals.h"
|
|
#include "vm/growable_array.h"
|
|
#include "vm/object.h"
|
|
#include "vm/token_position.h"
|
|
|
|
namespace dart {
|
|
namespace kernel {
|
|
class NameIndex {
|
|
public:
|
|
static const int kInvalidName = -1;
|
|
|
|
NameIndex() : value_(kInvalidName) {}
|
|
explicit NameIndex(int value) : value_(value) {}
|
|
|
|
operator int() const { return value_; }
|
|
|
|
private:
|
|
int value_;
|
|
};
|
|
} // namespace kernel
|
|
} // namespace dart
|
|
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
namespace dart {
|
|
|
|
class BitVector;
|
|
class Field;
|
|
class ParsedFunction;
|
|
class Zone;
|
|
|
|
namespace kernel {
|
|
|
|
class Reader;
|
|
struct ProcedureAttributesMetadata;
|
|
class TableSelectorMetadata;
|
|
|
|
class StringIndex {
|
|
public:
|
|
StringIndex() : value_(-1) {}
|
|
explicit StringIndex(int value) : value_(value) {}
|
|
|
|
operator int() const { return value_; }
|
|
|
|
private:
|
|
int value_;
|
|
};
|
|
|
|
const uint8_t kNativeYieldFlags = 0x2;
|
|
|
|
enum LogicalOperator { kAnd, kOr };
|
|
|
|
struct ProgramBinary {
|
|
ProgramBinary SubView(intptr_t start, intptr_t end) const {
|
|
return {typed_data, kernel_data + start, end - start};
|
|
}
|
|
|
|
const ExternalTypedData* typed_data;
|
|
const uint8_t* kernel_data;
|
|
intptr_t kernel_data_size;
|
|
};
|
|
|
|
class Program {
|
|
public:
|
|
// Read a kernel Program from the given Reader. Note the returned Program
|
|
// can potentially contain several "sub programs", though the library count
|
|
// etc will reference the last "sub program" only.
|
|
static std::unique_ptr<Program> ReadFrom(Reader* reader,
|
|
const char** error = nullptr);
|
|
|
|
static std::unique_ptr<Program> ReadFromFile(const char* script_uri,
|
|
const char** error = nullptr);
|
|
static std::unique_ptr<Program> ReadFromBuffer(const uint8_t* buffer,
|
|
intptr_t buffer_length,
|
|
const char** error = nullptr);
|
|
static std::unique_ptr<Program> ReadFromTypedData(
|
|
const ExternalTypedData& typed_data, const char** error = nullptr);
|
|
|
|
bool is_single_program() { return single_program_; }
|
|
uint32_t binary_version() { return binary_version_; }
|
|
NameIndex main_method() { return main_method_reference_; }
|
|
intptr_t source_table_offset() const { return source_table_offset_; }
|
|
intptr_t string_table_offset() const { return string_table_offset_; }
|
|
intptr_t name_table_offset() const { return name_table_offset_; }
|
|
intptr_t metadata_payloads_offset() const {
|
|
return metadata_payloads_offset_;
|
|
}
|
|
intptr_t metadata_mappings_offset() const {
|
|
return metadata_mappings_offset_;
|
|
}
|
|
intptr_t constant_table_offset() { return constant_table_offset_; }
|
|
intptr_t library_count() { return library_count_; }
|
|
NNBDCompiledMode compilation_mode() const { return compilation_mode_; }
|
|
|
|
const ProgramBinary& binary() const { return binary_; }
|
|
const ExternalTypedData* typed_data() { return binary().typed_data; }
|
|
const uint8_t* kernel_data() { return binary().kernel_data; }
|
|
intptr_t kernel_data_size() { return binary().kernel_data_size; }
|
|
|
|
private:
|
|
Program() : binary_() {}
|
|
|
|
bool single_program_;
|
|
uint32_t binary_version_;
|
|
NameIndex main_method_reference_; // Procedure.
|
|
NNBDCompiledMode compilation_mode_;
|
|
intptr_t library_count_;
|
|
|
|
// The offset from the start of the binary to the start of the source table.
|
|
intptr_t source_table_offset_;
|
|
|
|
// The offset from the start of the binary to the start of the constant table.
|
|
intptr_t constant_table_offset_;
|
|
|
|
// The offset from the start of the binary to the canonical name table.
|
|
intptr_t name_table_offset_;
|
|
|
|
// The offset from the start of the binary to the metadata payloads.
|
|
intptr_t metadata_payloads_offset_;
|
|
|
|
// The offset from the start of the binary to the metadata mappings.
|
|
intptr_t metadata_mappings_offset_;
|
|
|
|
// The offset from the start of the binary to the start of the string table.
|
|
intptr_t string_table_offset_;
|
|
|
|
ProgramBinary binary_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(Program);
|
|
};
|
|
|
|
class KernelLineStartsReader {
|
|
public:
|
|
KernelLineStartsReader(const dart::TypedData& line_starts_data,
|
|
dart::Zone* zone);
|
|
|
|
~KernelLineStartsReader() { delete helper_; }
|
|
|
|
int32_t DeltaAt(intptr_t index) const {
|
|
return helper_->At(line_starts_data_, index);
|
|
}
|
|
|
|
int32_t MaxPosition() const;
|
|
|
|
// Returns whether the given offset corresponds to a valid source offset
|
|
// If it does, then *line and *column (if column is not nullptr) are set
|
|
// to the line and column the token starts at.
|
|
DART_WARN_UNUSED_RESULT bool LocationForPosition(
|
|
intptr_t position,
|
|
intptr_t* line,
|
|
intptr_t* col = nullptr) const;
|
|
|
|
// Returns whether any tokens were found for the given line. When found,
|
|
// *first_token_index and *last_token_index are set to the first and
|
|
// last token on the line, respectively.
|
|
DART_WARN_UNUSED_RESULT bool TokenRangeAtLine(
|
|
intptr_t line_number,
|
|
dart::TokenPosition* first_token_index,
|
|
dart::TokenPosition* last_token_index) const;
|
|
|
|
private:
|
|
class KernelLineStartsHelper {
|
|
public:
|
|
KernelLineStartsHelper() {}
|
|
virtual ~KernelLineStartsHelper() {}
|
|
virtual int32_t At(const dart::TypedData& data, intptr_t index) const = 0;
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(KernelLineStartsHelper);
|
|
};
|
|
|
|
class KernelInt8LineStartsHelper : public KernelLineStartsHelper {
|
|
public:
|
|
KernelInt8LineStartsHelper() {}
|
|
virtual int32_t At(const dart::TypedData& data, intptr_t index) const;
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(KernelInt8LineStartsHelper);
|
|
};
|
|
|
|
class KernelInt16LineStartsHelper : public KernelLineStartsHelper {
|
|
public:
|
|
KernelInt16LineStartsHelper() {}
|
|
virtual int32_t At(const dart::TypedData& data, intptr_t index) const;
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(KernelInt16LineStartsHelper);
|
|
};
|
|
|
|
class KernelInt32LineStartsHelper : public KernelLineStartsHelper {
|
|
public:
|
|
KernelInt32LineStartsHelper() {}
|
|
virtual int32_t At(const dart::TypedData& data, intptr_t index) const;
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(KernelInt32LineStartsHelper);
|
|
};
|
|
|
|
const dart::TypedData& line_starts_data_;
|
|
KernelLineStartsHelper* helper_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(KernelLineStartsReader);
|
|
};
|
|
|
|
void CollectTokenPositionsFor(const Script& script);
|
|
|
|
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
|
ArrayPtr CollectConstConstructorCoverageFrom(const Script& interesting_script);
|
|
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
|
|
|
ObjectPtr EvaluateStaticConstFieldInitializer(const Field& field);
|
|
ObjectPtr EvaluateMetadata(const Library& library,
|
|
intptr_t kernel_offset,
|
|
bool is_annotations_offset);
|
|
ObjectPtr BuildParameterDescriptor(const Function& function);
|
|
|
|
// Fills in [is_covariant] and [is_generic_covariant_impl] vectors
|
|
// according to covariance attributes of [function] parameters.
|
|
//
|
|
// [is_covariant] and [is_generic_covariant_impl] should contain bitvectors
|
|
// of function.NumParameters() length.
|
|
void ReadParameterCovariance(const Function& function,
|
|
BitVector* is_covariant,
|
|
BitVector* is_generic_covariant_impl);
|
|
|
|
// Returns true if the given function needs dynamic invocation forwarder:
|
|
// that is if any of the arguments require checking on the dynamic
|
|
// call-site: if function has no parameters or has only covariant parameters
|
|
// as such function already checks all of its parameters.
|
|
bool NeedsDynamicInvocationForwarder(const Function& function);
|
|
|
|
ProcedureAttributesMetadata ProcedureAttributesOf(const Function& function,
|
|
Zone* zone);
|
|
|
|
ProcedureAttributesMetadata ProcedureAttributesOf(const Field& field,
|
|
Zone* zone);
|
|
|
|
TableSelectorMetadata* TableSelectorMetadataForProgram(
|
|
const KernelProgramInfo& info,
|
|
Zone* zone);
|
|
|
|
} // namespace kernel
|
|
} // namespace dart
|
|
|
|
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
|
#endif // RUNTIME_VM_KERNEL_H_
|