Commit 5cc245ae authored by Dan Elphick's avatar Dan Elphick Committed by Commit Bot

[compile] Add support for lazy generation of source position tables

If enable_omit_source_positions is true (defaults to false), source
position tables are not generated when compiling bytecode. They will
then be regenerated when exceptions are thrown.

This adds a new function Compiler::CollectSourcePositions which given a
SharedFunctionInfo with bytecode but no source position table re-parses
and regenerates the bytecode but this time with source positions
collection enabled. Note this will reparse all inner functions that
have previously been compiled since the preparse data is no longer
available.

With the flag enabled there still 18 test failures mostly related to
debugging.

v8: 8510
Change-Id: I46dff9818d8a89c901ba8ae8df94dcaca83aa658
Reviewed-on: https://chromium-review.googlesource.com/c/1385165
Commit-Queue: Dan Elphick <delphick@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59595}
parent 6cb174b4
......@@ -9609,8 +9609,11 @@ debug::Location debug::GeneratorObject::SuspendedLocation() {
CHECK(obj->is_suspended());
i::Object maybe_script = obj->function()->shared()->script();
if (!maybe_script->IsScript()) return debug::Location();
i::Handle<i::Script> script(i::Script::cast(maybe_script), obj->GetIsolate());
i::Isolate* isolate = obj->GetIsolate();
i::Handle<i::Script> script(i::Script::cast(maybe_script), isolate);
i::Script::PositionInfo info;
i::SharedFunctionInfo::EnsureSourcePositionsAvailable(
isolate, i::handle(obj->function()->shared(), isolate));
i::Script::GetPositionInfo(script, obj->source_position(), &info,
i::Script::WITH_OFFSET);
return debug::Location(info.line, info.column);
......
......@@ -1118,6 +1118,89 @@ bool Compiler::ParseAndAnalyze(ParseInfo* parse_info,
return Compiler::Analyze(parse_info);
}
// static
bool Compiler::CollectSourcePositions(Isolate* isolate,
Handle<SharedFunctionInfo> shared_info) {
DCHECK(shared_info->is_compiled());
DCHECK(shared_info->HasBytecodeArray());
DCHECK(!shared_info->GetBytecodeArray()->HasSourcePositionTable());
// TODO(v8:8510): Push the CLEAR_EXCEPTION flag or something like it down into
// the parser so it aborts without setting a pending exception, which then
// gets thrown. This would avoid the situation where potentially we'd reparse
// several times (running out of stack each time) before hitting this limit.
if (GetCurrentStackPosition() < isolate->stack_guard()->real_climit())
return false;
DCHECK(AllowCompilation::IsAllowed(isolate));
DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
DCHECK(!isolate->has_pending_exception());
VMState<BYTECODE_COMPILER> state(isolate);
PostponeInterruptsScope postpone(isolate);
RuntimeCallTimerScope runtimeTimer(
isolate, RuntimeCallCounterId::kCompileCollectSourcePositions);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.CollectSourcePositions");
HistogramTimerScope timer(isolate->counters()->collect_source_positions());
// Set up parse info.
ParseInfo parse_info(isolate, shared_info);
parse_info.set_lazy_compile();
parse_info.set_collect_source_positions();
if (FLAG_allow_natives_syntax) parse_info.set_allow_natives_syntax();
// Parse and update ParseInfo with the results.
if (!parsing::ParseAny(&parse_info, shared_info, isolate)) {
return FailWithPendingException(
isolate, &parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION);
}
// Generate the unoptimized bytecode.
// TODO(v8:8510): Consider forcing preparsing of inner functions to avoid
// wasting time fully parsing them when they won't ever be used.
UnoptimizedCompilationJobList inner_function_jobs;
std::unique_ptr<UnoptimizedCompilationJob> outer_function_job(
GenerateUnoptimizedCode(&parse_info, isolate->allocator(),
&inner_function_jobs));
if (!outer_function_job) {
return FailWithPendingException(
isolate, &parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION);
}
DCHECK(outer_function_job->compilation_info()->collect_source_positions());
// TODO(v8:8510) Avoid re-allocating bytecode array/constant pool and
// re-internalizeing the ast values. Maybe we could use the
// unoptimized_compilation_flag to signal that all we need is the source
// position table (and we could do the DCHECK that the bytecode array is the
// same in the bytecode-generator, by comparing the real bytecode array on the
// SFI with the off-heap bytecode array).
// Internalize ast values onto the heap.
parse_info.ast_value_factory()->Internalize(isolate);
{
// Allocate scope infos for the literal.
DeclarationScope::AllocateScopeInfos(&parse_info, isolate);
CHECK_EQ(outer_function_job->FinalizeJob(shared_info, isolate),
CompilationJob::SUCCEEDED);
}
// Update the source position table on the original bytecode.
Handle<BytecodeArray> bytecode =
handle(shared_info->GetBytecodeArray(), isolate);
DCHECK(bytecode->IsBytecodeEqual(
*outer_function_job->compilation_info()->bytecode_array()));
DCHECK(outer_function_job->compilation_info()->has_bytecode_array());
bytecode->set_source_position_table(outer_function_job->compilation_info()
->bytecode_array()
->SourcePositionTable());
DCHECK(!isolate->has_pending_exception());
DCHECK(shared_info->is_compiled_scope().is_compiled());
return true;
}
bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
ClearExceptionFlag flag,
IsCompiledScope* is_compiled_scope) {
......
......@@ -64,6 +64,12 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
IsCompiledScope* is_compiled_scope);
static bool CompileOptimized(Handle<JSFunction> function, ConcurrencyMode);
// Collect source positions for a function that has already been compiled to
// bytecode, but for which source positions were not collected (e.g. because
// they were not immediately needed).
static bool CollectSourcePositions(Isolate* isolate,
Handle<SharedFunctionInfo> shared);
V8_WARN_UNUSED_RESULT static MaybeHandle<SharedFunctionInfo>
CompileForLiveEdit(ParseInfo* parse_info, Isolate* isolate);
......
......@@ -880,6 +880,7 @@ class RuntimeCallTimer final {
V(CompileBackgroundRewriteReturnResult) \
V(CompileBackgroundScopeAnalysis) \
V(CompileBackgroundScript) \
V(CompileCollectSourcePositions) \
V(CompileDeserialize) \
V(CompileEnqueueOnDispatcher) \
V(CompileEval) \
......@@ -1246,6 +1247,8 @@ class RuntimeCallTimerScope {
HT(gc_low_memory_notification, V8.GCLowMemoryNotification, 10000, \
MILLISECOND) \
/* Compilation times. */ \
HT(collect_source_positions, V8.CollectSourcePositions, 1000000, \
MICROSECOND) \
HT(compile, V8.CompileMicroSeconds, 1000000, MICROSECOND) \
HT(compile_eval, V8.CompileEvalMicroSeconds, 1000000, MICROSECOND) \
/* Serialization as part of compilation (code caching) */ \
......
......@@ -519,6 +519,8 @@ int ScopeIterator::GetSourcePosition() {
return frame_inspector_->GetSourcePosition();
} else {
DCHECK(!generator_.is_null());
SharedFunctionInfo::EnsureSourcePositionsAvailable(
isolate_, handle(generator_->function()->shared(), isolate_));
return generator_->source_position();
}
}
......
......@@ -355,6 +355,9 @@ DEFINE_BOOL(ignition_share_named_property_feedback, true,
"the same object")
DEFINE_BOOL(print_bytecode, false,
"print bytecode generated by ignition interpreter")
DEFINE_BOOL(enable_lazy_source_positions, false,
"skip generating source positions during initial compile but "
"regenerate when actually required")
DEFINE_STRING(print_bytecode_filter, "*",
"filter for selecting which functions to print bytecode")
#ifdef V8_TRACE_IGNITION
......
......@@ -1303,6 +1303,11 @@ FrameSummary::JavaScriptFrameSummary::JavaScriptFrameSummary(
parameters_(parameters, isolate) {
DCHECK(abstract_code->IsBytecodeArray() ||
Code::cast(abstract_code)->kind() != Code::OPTIMIZED_FUNCTION);
// TODO(v8:8510): Move this to the SourcePosition getter.
if (FLAG_enable_lazy_source_positions && abstract_code->IsBytecodeArray()) {
SharedFunctionInfo::EnsureSourcePositionsAvailable(
isolate, handle(function->shared(), isolate));
}
}
bool FrameSummary::JavaScriptFrameSummary::is_subject_to_debugging() const {
......
......@@ -1820,7 +1820,7 @@ Handle<BytecodeArray> Factory::NewBytecodeArray(
instance->set_bytecode_age(BytecodeArray::kNoAgeBytecodeAge);
instance->set_constant_pool(*constant_pool);
instance->set_handler_table(*empty_byte_array());
instance->set_source_position_table(*empty_byte_array());
instance->set_source_position_table(*undefined_value());
CopyBytes(reinterpret_cast<byte*>(instance->GetFirstBytecodeAddress()),
raw_bytecodes, length);
instance->clear_padding();
......
......@@ -45,16 +45,20 @@ Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray(
int frame_size = register_count * kSystemPointerSize;
Handle<FixedArray> constant_pool =
constant_array_builder()->ToFixedArray(isolate);
Handle<ByteArray> source_position_table =
source_position_table_builder()->ToSourcePositionTable(isolate);
Handle<BytecodeArray> bytecode_array = isolate->factory()->NewBytecodeArray(
bytecode_size, &bytecodes()->front(), frame_size, parameter_count,
constant_pool);
bytecode_array->set_handler_table(*handler_table);
bytecode_array->set_source_position_table(*source_position_table);
LOG_CODE_EVENT(isolate, CodeLinePosInfoRecordEvent(
bytecode_array->GetFirstBytecodeAddress(),
*source_position_table));
// TODO(v8:8510): Need to support native functions that should always have
// source positions suppressed and should write empty_byte_array here.
if (!source_position_table_builder_.Omit()) {
Handle<ByteArray> source_position_table =
source_position_table_builder()->ToSourcePositionTable(isolate);
bytecode_array->set_source_position_table(*source_position_table);
LOG_CODE_EVENT(isolate, CodeLinePosInfoRecordEvent(
bytecode_array->GetFirstBytecodeAddress(),
*source_position_table));
}
return bytecode_array;
}
......
......@@ -782,16 +782,25 @@ void JSGeneratorObject::JSGeneratorObjectPrint(std::ostream& os) { // NOLINT
SharedFunctionInfo fun_info = function()->shared();
if (fun_info->HasSourceCode()) {
Script script = Script::cast(fun_info->script());
int lin = script->GetLineNumber(source_position()) + 1;
int col = script->GetColumnNumber(source_position()) + 1;
String script_name = script->name()->IsString()
? String::cast(script->name())
: GetReadOnlyRoots().empty_string();
os << "\n - source position: " << source_position();
os << " (";
script_name->PrintUC16(os);
os << ", lin " << lin;
os << ", col " << col;
os << "\n - source position: ";
// Can't collect source positions here if not available as that would
// allocate memory.
if (fun_info->HasBytecodeArray() &&
fun_info->GetBytecodeArray()->HasSourcePositionTable()) {
os << source_position();
os << " (";
script_name->PrintUC16(os);
int lin = script->GetLineNumber(source_position()) + 1;
int col = script->GetColumnNumber(source_position()) + 1;
os << ", lin " << lin;
os << ", col " << col;
} else {
os << "unavailable";
}
os << ")";
}
}
......
......@@ -5508,6 +5508,25 @@ void SharedFunctionInfo::SetPosition(int start_position, int end_position) {
}
}
// static
void SharedFunctionInfo::EnsureSourcePositionsAvailable(
Isolate* isolate, Handle<SharedFunctionInfo> shared_info) {
if (FLAG_enable_lazy_source_positions && shared_info->HasBytecodeArray() &&
!shared_info->GetBytecodeArray()->HasSourcePositionTable()) {
Compiler::CollectSourcePositions(isolate, shared_info);
}
}
bool BytecodeArray::IsBytecodeEqual(const BytecodeArray other) const {
if (length() != other->length()) return false;
for (int i = 0; i < length(); ++i) {
if (get(i) != other->get(i)) return false;
}
return true;
}
// static
void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
DCHECK_GE(capacity, 0);
......@@ -8131,6 +8150,7 @@ void PropertyCell::SetValueWithInvalidation(Isolate* isolate,
int JSGeneratorObject::source_position() const {
CHECK(is_suspended());
DCHECK(function()->shared()->HasBytecodeArray());
DCHECK(function()->shared()->GetBytecodeArray()->HasSourcePositionTable());
int code_offset = Smi::ToInt(input_or_debug_pos());
......
......@@ -603,7 +603,7 @@ void CodeDataContainer::clear_padding() {
kSize - kUnalignedSize);
}
byte BytecodeArray::get(int index) {
byte BytecodeArray::get(int index) const {
DCHECK(index >= 0 && index < this->length());
return READ_BYTE_FIELD(*this, kHeaderSize + index * kCharSize);
}
......@@ -712,9 +712,17 @@ Address BytecodeArray::GetFirstBytecodeAddress() {
return ptr() - kHeapObjectTag + kHeaderSize;
}
bool BytecodeArray::HasSourcePositionTable() {
Object maybe_table = source_position_table();
return !maybe_table->IsUndefined();
}
ByteArray BytecodeArray::SourcePositionTable() {
Object maybe_table = source_position_table();
if (maybe_table->IsByteArray()) return ByteArray::cast(maybe_table);
ReadOnlyRoots roots = GetReadOnlyRoots();
if (maybe_table->IsUndefined(roots)) return roots.empty_byte_array();
DCHECK(maybe_table->IsSourcePositionTableWithFrameCache());
return SourcePositionTableWithFrameCache::cast(maybe_table)
->source_position_table();
......@@ -722,7 +730,7 @@ ByteArray BytecodeArray::SourcePositionTable() {
void BytecodeArray::ClearFrameCacheFromSourcePositionTable() {
Object maybe_table = source_position_table();
if (maybe_table->IsByteArray()) return;
if (maybe_table->IsUndefined() || maybe_table->IsByteArray()) return;
DCHECK(maybe_table->IsSourcePositionTableWithFrameCache());
set_source_position_table(SourcePositionTableWithFrameCache::cast(maybe_table)
->source_position_table());
......
......@@ -165,7 +165,7 @@ void SetStackFrameCacheCommon(Isolate* isolate, Handle<Code> code,
->set_stack_frame_cache(*cache);
return;
}
DCHECK(maybe_table->IsByteArray());
DCHECK(maybe_table->IsUndefined() || maybe_table->IsByteArray());
Handle<ByteArray> table(Handle<ByteArray>::cast(maybe_table));
Handle<SourcePositionTableWithFrameCache> table_with_cache =
isolate->factory()->NewSourcePositionTableWithFrameCache(table, cache);
......@@ -192,7 +192,7 @@ namespace {
template <typename Code>
void DropStackFrameCacheCommon(Code code) {
i::Object maybe_table = code->source_position_table();
if (maybe_table->IsByteArray()) return;
if (maybe_table->IsUndefined() || maybe_table->IsByteArray()) return;
DCHECK(maybe_table->IsSourcePositionTableWithFrameCache());
code->set_source_position_table(
i::SourcePositionTableWithFrameCache::cast(maybe_table)
......
......@@ -737,7 +737,7 @@ class BytecodeArray : public FixedArrayBase {
}
// Setter and getter
inline byte get(int index);
inline byte get(int index) const;
inline void set(int index, byte value);
// Returns data start address.
......@@ -784,6 +784,7 @@ class BytecodeArray : public FixedArrayBase {
DECL_ACCESSORS(source_position_table, Object)
inline ByteArray SourcePositionTable();
inline bool HasSourcePositionTable();
inline void ClearFrameCacheFromSourcePositionTable();
DECL_CAST(BytecodeArray)
......@@ -815,6 +816,9 @@ class BytecodeArray : public FixedArrayBase {
// is deterministic.
inline void clear_padding();
// Compares only the bytecode array but not any of the header fields.
bool IsBytecodeEqual(const BytecodeArray other) const;
// Layout description.
#define BYTECODE_ARRAY_FIELDS(V) \
/* Pointer fields. */ \
......
......@@ -584,6 +584,9 @@ class SharedFunctionInfo : public HeapObject {
void SetFunctionTokenPosition(int function_token_position,
int start_position);
static void EnsureSourcePositionsAvailable(
Isolate* isolate, Handle<SharedFunctionInfo> shared_info);
inline bool construct_as_builtin() const;
// Determines and sets the ConstructAsBuiltinBit in |flags|, based on the
......
......@@ -48,6 +48,8 @@ ParseInfo::ParseInfo(Isolate* isolate, AccountingAllocator* zone_allocator)
set_runtime_call_stats(isolate->counters()->runtime_call_stats());
set_logger(isolate->logger());
set_ast_string_constants(isolate->ast_string_constants());
set_collect_source_positions(!FLAG_enable_lazy_source_positions ||
isolate->NeedsDetailedOptimizedCodeLineInfo());
if (isolate->is_block_code_coverage()) set_block_coverage_enabled();
if (isolate->is_collecting_type_profile()) set_collect_type_profile();
if (isolate->compiler_dispatcher()->IsEnabled()) {
......
......@@ -116,6 +116,8 @@ class V8_EXPORT_PRIVATE ParseInfo {
FLAG_ACCESSOR(kAllowHarmonyPrivateMethods, allow_harmony_private_methods,
set_allow_harmony_private_methods)
FLAG_ACCESSOR(kIsOneshotIIFE, is_oneshot_iife, set_is_oneshot_iife)
FLAG_ACCESSOR(kCollectSourcePositions, collect_source_positions,
set_collect_source_positions)
#undef FLAG_ACCESSOR
void set_parse_restriction(ParseRestriction restriction) {
......@@ -312,7 +314,8 @@ class V8_EXPORT_PRIVATE ParseInfo {
kAllowHarmonyNumericSeparator = 1 << 26,
kAllowHarmonyPrivateFields = 1 << 27,
kAllowHarmonyPrivateMethods = 1 << 28,
kIsOneshotIIFE = 1 << 29
kIsOneshotIIFE = 1 << 29,
kCollectSourcePositions = 1 << 30,
};
//------------- Inputs to parsing and scope analysis -----------------------
......
......@@ -44,11 +44,11 @@ class V8_EXPORT_PRIVATE SourcePositionTableBuilder {
Handle<ByteArray> ToSourcePositionTable(Isolate* isolate);
OwnedVector<byte> ToSourcePositionTableVector();
inline bool Omit() const { return mode_ == OMIT_SOURCE_POSITIONS; }
private:
void AddEntry(const PositionTableEntry& entry);
inline bool Omit() const { return mode_ == OMIT_SOURCE_POSITIONS; }
RecordingMode mode_;
std::vector<byte> bytes_;
#ifdef ENABLE_SLOW_DCHECKS
......
......@@ -33,6 +33,9 @@ UnoptimizedCompilationInfo::UnoptimizedCompilationInfo(Zone* zone,
if (parse_info->is_native()) MarkAsNative();
if (parse_info->collect_type_profile()) MarkAsCollectTypeProfile();
if (parse_info->might_always_opt()) MarkAsMightAlwaysOpt();
if (parse_info->collect_source_positions()) {
MarkAsForceCollectSourcePositions();
}
}
DeclarationScope* UnoptimizedCompilationInfo::scope() const {
......@@ -50,8 +53,20 @@ int UnoptimizedCompilationInfo::num_parameters_including_this() const {
SourcePositionTableBuilder::RecordingMode
UnoptimizedCompilationInfo::SourcePositionRecordingMode() const {
return is_native() ? SourcePositionTableBuilder::OMIT_SOURCE_POSITIONS
: SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS;
if (is_native()) {
DCHECK(!collect_source_positions());
return SourcePositionTableBuilder::OMIT_SOURCE_POSITIONS;
}
if (collect_source_positions()) {
return SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS;
}
// Always collect source positions for functions that cannot be lazily
// compiled, e.g. class member initializer functions.
return !literal_->AllowsLazyCompilation()
? SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS
: SourcePositionTableBuilder::OMIT_SOURCE_POSITIONS;
}
} // namespace internal
......
......@@ -46,6 +46,11 @@ class V8_EXPORT_PRIVATE UnoptimizedCompilationInfo final {
void MarkAsCollectTypeProfile() { SetFlag(kCollectTypeProfile); }
bool collect_type_profile() const { return GetFlag(kCollectTypeProfile); }
void MarkAsForceCollectSourcePositions() { SetFlag(kCollectSourcePositions); }
bool collect_source_positions() const {
return GetFlag(kCollectSourcePositions);
}
void MarkAsMightAlwaysOpt() { SetFlag(kMightAlwaysOpt); }
bool might_always_opt() const { return GetFlag(kMightAlwaysOpt); }
......@@ -102,6 +107,7 @@ class V8_EXPORT_PRIVATE UnoptimizedCompilationInfo final {
kIsNative = 1 << 1,
kCollectTypeProfile = 1 << 2,
kMightAlwaysOpt = 1 << 3,
kCollectSourcePositions = 1 << 4,
};
void SetFlag(Flag flag) { flags_ |= flag; }
......
......@@ -91,6 +91,7 @@ class InitializedIgnitionHandleScope : public InitializedHandleScope {
InitializedIgnitionHandleScope() {
i::FLAG_always_opt = false;
i::FLAG_allow_natives_syntax = true;
i::FLAG_enable_lazy_source_positions = false;
}
};
......
......@@ -8,6 +8,7 @@
#include "src/api-inl.h"
#include "src/base/overflowing-math.h"
#include "src/compiler.h"
#include "src/execution.h"
#include "src/handles.h"
#include "src/interpreter/bytecode-array-builder.h"
......@@ -5059,6 +5060,82 @@ TEST(InterpreterGetBytecodeHandler) {
CHECK_EQ(add_wide_handler->builtin_index(), Builtins::kAddWideHandler);
}
TEST(InterpreterCollectSourcePositions) {
FLAG_enable_lazy_source_positions = true;
HandleAndZoneScope handles;
Isolate* isolate = handles.main_isolate();
const char* source =
"(function () {\n"
" return 1;\n"
"})";
Handle<JSFunction> function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast(CompileRun(source))));
Handle<SharedFunctionInfo> sfi = handle(function->shared(), isolate);
Handle<BytecodeArray> bytecode_array =
handle(sfi->GetBytecodeArray(), isolate);
ByteArray source_position_table = bytecode_array->SourcePositionTable();
CHECK_EQ(source_position_table->length(), 0);
Compiler::CollectSourcePositions(isolate, sfi);
source_position_table = bytecode_array->SourcePositionTable();
CHECK_GT(source_position_table->length(), 0);
}
namespace {
void CheckStringEqual(const char* expected_ptr, Handle<Object> actual_handle) {
v8::String::Utf8Value utf8(
v8::Isolate::GetCurrent(),
v8::Utils::ToLocal(Handle<String>::cast(actual_handle)));
std::string expected(expected_ptr);
std::string actual(*utf8);
CHECK_EQ(expected, actual);
}
} // namespace
TEST(InterpreterCollectSourcePositions_GenerateStackTrace) {
FLAG_enable_lazy_source_positions = true;
HandleAndZoneScope handles;
Isolate* isolate = handles.main_isolate();
const char* source =
R"javascript(
(function () {
try {
throw new Error();
} catch (e) {
return e.stack;
}
});
)javascript";
Handle<JSFunction> function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast(CompileRun(source))));
Handle<SharedFunctionInfo> sfi = handle(function->shared(), isolate);
Handle<BytecodeArray> bytecode_array =
handle(sfi->GetBytecodeArray(), isolate);
ByteArray source_position_table = bytecode_array->SourcePositionTable();
CHECK_EQ(source_position_table->length(), 0);
{
Handle<Object> result =
Execution::Call(isolate, function,
ReadOnlyRoots(isolate).undefined_value_handle(), 0,
nullptr)
.ToHandleChecked();
CheckStringEqual("Error\n at <anonymous>:4:17", result);
}
source_position_table = bytecode_array->SourcePositionTable();
CHECK_GT(source_position_table->length(), 0);
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -113,6 +113,7 @@ class OptimizedBytecodeSourcePositionTester final {
SaveOptimizationFlags();
saved_flag_always_opt_ = FLAG_always_opt;
FLAG_always_opt = false;
FLAG_enable_lazy_source_positions = false;
}
~OptimizedBytecodeSourcePositionTester() {
......
......@@ -2693,6 +2693,9 @@ TEST(TrackHeapAllocationsWithInlining) {
CHECK(node);
// In lite mode, there is feedback and feedback metadata.
unsigned int num_nodes = (i::FLAG_lite_mode) ? 6 : 8;
// Without forced source position collection, there is no source position
// table.
if (i::FLAG_enable_lazy_source_positions) num_nodes -= 1;
CHECK_GE(node->allocation_count(), num_nodes);
CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
heap_profiler->StopTrackingHeapObjects();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment