blob: 7b7ac73c271c8056ea0c1f9605f5ead00573fc83 [file] [log] [blame]
// 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.
#include "vm/kernel.h"
#include "vm/compiler/frontend/kernel_binary_flowgraph.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
namespace dart {
namespace kernel {
bool FieldHasFunctionLiteralInitializer(const Field& field,
TokenPosition* start,
TokenPosition* end) {
Zone* zone = Thread::Current()->zone();
const Script& script = Script::Handle(zone, field.Script());
TranslationHelper translation_helper(Thread::Current());
translation_helper.InitFromScript(script);
StreamingFlowGraphBuilder builder(&translation_helper,
Script::Handle(zone, field.Script()), zone,
TypedData::Handle(zone, field.KernelData()),
field.KernelDataProgramOffset(),
/* active_class = */ NULL);
builder.SetOffset(field.kernel_offset());
kernel::FieldHelper field_helper(&builder);
field_helper.ReadUntilExcluding(kernel::FieldHelper::kEnd, true);
return field_helper.FieldHasFunctionLiteralInitializer(start, end);
}
uint32_t KernelSourceFingerprintHelper::CalculateClassFingerprint(
const Class& klass) {
Zone* zone = Thread::Current()->zone();
// Handle typedefs.
if (klass.IsTypedefClass()) {
const Function& func = Function::Handle(zone, klass.signature_function());
return CalculateFunctionFingerprint(func);
}
String& name = String::Handle(zone, klass.Name());
const Array& fields = Array::Handle(zone, klass.fields());
const Array& functions = Array::Handle(zone, klass.functions());
const Array& interfaces = Array::Handle(zone, klass.interfaces());
AbstractType& type = AbstractType::Handle(zone);
uint32_t hash = 0;
hash = KernelFingerprintHelper::CalculateHash(hash, name.Hash());
type ^= klass.super_type();
if (!type.IsNull()) {
name ^= type.Name();
hash = KernelFingerprintHelper::CalculateHash(hash, name.Hash());
}
type ^= klass.mixin();
if (!type.IsNull()) {
name ^= type.Name();
hash = KernelFingerprintHelper::CalculateHash(hash, name.Hash());
}
Field& field = Field::Handle(zone);
// Calculate fingerprint for the class fields.
for (intptr_t i = 0; i < fields.Length(); ++i) {
field ^= fields.At(i);
uint32_t fingerprint = CalculateFieldFingerprint(field);
hash = KernelFingerprintHelper::CalculateHash(hash, fingerprint);
}
// Calculate fingerprint for the class functions.
Function& func = Function::Handle(zone);
for (intptr_t i = 0; i < functions.Length(); ++i) {
func ^= functions.At(i);
uint32_t fingerprint = CalculateFunctionFingerprint(func);
hash = KernelFingerprintHelper::CalculateHash(hash, fingerprint);
}
// Calculate fingerprint for the interfaces.
for (intptr_t i = 0; i < interfaces.Length(); ++i) {
type ^= interfaces.At(i);
name ^= type.Name();
hash = KernelFingerprintHelper::CalculateHash(hash, name.Hash());
}
return hash;
}
uint32_t KernelSourceFingerprintHelper::CalculateFieldFingerprint(
const Field& field) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Script& script = Script::Handle(zone, field.Script());
TranslationHelper translation_helper(thread);
translation_helper.InitFromScript(script);
KernelFingerprintHelper helper(zone, &translation_helper, script,
TypedData::Handle(zone, field.KernelData()),
field.KernelDataProgramOffset());
helper.SetOffset(field.kernel_offset());
return helper.CalculateFieldFingerprint();
}
uint32_t KernelSourceFingerprintHelper::CalculateFunctionFingerprint(
const Function& func) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Script& script = Script::Handle(zone, func.script());
TranslationHelper translation_helper(thread);
translation_helper.InitFromScript(script);
KernelFingerprintHelper helper(zone, &translation_helper, script,
TypedData::Handle(zone, func.KernelData()),
func.KernelDataProgramOffset());
helper.SetOffset(func.kernel_offset());
return helper.CalculateFunctionFingerprint();
}
KernelLineStartsReader::KernelLineStartsReader(
const dart::TypedData& line_starts_data,
dart::Zone* zone)
: line_starts_data_(line_starts_data) {
TypedDataElementType type = line_starts_data_.ElementType();
if (type == kInt8ArrayElement) {
helper_ = new KernelInt8LineStartsHelper();
} else if (type == kInt16ArrayElement) {
helper_ = new KernelInt16LineStartsHelper();
} else if (type == kInt32ArrayElement) {
helper_ = new KernelInt32LineStartsHelper();
} else {
UNREACHABLE();
}
}
intptr_t KernelLineStartsReader::LineNumberForPosition(
intptr_t position) const {
intptr_t line_count = line_starts_data_.Length();
intptr_t current_start = 0;
for (intptr_t i = 0; i < line_count; ++i) {
current_start += helper_->At(line_starts_data_, i);
if (current_start > position) {
// If current_start is greater than the desired position, it means that
// it is for the line after |position|. However, since line numbers
// start at 1, we just return |i|.
return i;
}
if (current_start == position) {
return i + 1;
}
}
return line_count;
}
void KernelLineStartsReader::LocationForPosition(intptr_t position,
intptr_t* line,
intptr_t* col) const {
intptr_t line_count = line_starts_data_.Length();
intptr_t current_start = 0;
intptr_t previous_start = 0;
for (intptr_t i = 0; i < line_count; ++i) {
current_start += helper_->At(line_starts_data_, i);
if (current_start > position) {
*line = i;
if (col != NULL) {
*col = position - previous_start + 1;
}
return;
}
if (current_start == position) {
*line = i + 1;
if (col != NULL) {
*col = 1;
}
return;
}
previous_start = current_start;
}
// If the start of any of the lines did not cross |position|,
// then it means the position falls on the last line.
*line = line_count;
if (col != NULL) {
*col = position - current_start + 1;
}
}
void KernelLineStartsReader::TokenRangeAtLine(
intptr_t source_length,
intptr_t line_number,
TokenPosition* first_token_index,
TokenPosition* last_token_index) const {
ASSERT(line_number <= line_starts_data_.Length());
intptr_t cumulative = 0;
for (intptr_t i = 0; i < line_number; ++i) {
cumulative += helper_->At(line_starts_data_, i);
}
*first_token_index = dart::TokenPosition(cumulative);
if (line_number == line_starts_data_.Length()) {
*last_token_index = dart::TokenPosition(source_length);
} else {
*last_token_index = dart::TokenPosition(
cumulative + helper_->At(line_starts_data_, line_number) - 1);
}
}
int32_t KernelLineStartsReader::KernelInt8LineStartsHelper::At(
const dart::TypedData& data,
intptr_t index) const {
return data.GetInt8(index);
}
int32_t KernelLineStartsReader::KernelInt16LineStartsHelper::At(
const dart::TypedData& data,
intptr_t index) const {
return data.GetInt16(index << 1);
}
int32_t KernelLineStartsReader::KernelInt32LineStartsHelper::At(
const dart::TypedData& data,
intptr_t index) const {
return data.GetInt32(index << 2);
}
} // namespace kernel
} // namespace dart
#endif // !defined(DART_PRECOMPILED_RUNTIME)