[inspector] Remove Type Profiler
See https://docs.google.com/document/d/1dJHFRXKE4NUchvYweuyzsolXDEWACr-jJZEPyC6f9EQ/edit?usp=sharing Change-Id: Ie5b30db30d55ba701a336d8a59dbff7771276e96 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3936281 Reviewed-by: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Maya Lekova <mslekova@chromium.org> Commit-Queue: Marja Hölttä <marja@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/main@{#83593}
This commit is contained in:
parent
4e2ecbd2d7
commit
283791d250
@ -1270,8 +1270,6 @@ filegroup(
|
|||||||
"src/debug/debug-scopes.h",
|
"src/debug/debug-scopes.h",
|
||||||
"src/debug/debug-stack-trace-iterator.cc",
|
"src/debug/debug-stack-trace-iterator.cc",
|
||||||
"src/debug/debug-stack-trace-iterator.h",
|
"src/debug/debug-stack-trace-iterator.h",
|
||||||
"src/debug/debug-type-profile.cc",
|
|
||||||
"src/debug/debug-type-profile.h",
|
|
||||||
"src/debug/debug.cc",
|
"src/debug/debug.cc",
|
||||||
"src/debug/debug.h",
|
"src/debug/debug.h",
|
||||||
"src/debug/interface-types.h",
|
"src/debug/interface-types.h",
|
||||||
|
2
BUILD.gn
2
BUILD.gn
@ -2949,7 +2949,6 @@ v8_header_set("v8_internal_headers") {
|
|||||||
"src/debug/debug-scope-iterator.h",
|
"src/debug/debug-scope-iterator.h",
|
||||||
"src/debug/debug-scopes.h",
|
"src/debug/debug-scopes.h",
|
||||||
"src/debug/debug-stack-trace-iterator.h",
|
"src/debug/debug-stack-trace-iterator.h",
|
||||||
"src/debug/debug-type-profile.h",
|
|
||||||
"src/debug/debug.h",
|
"src/debug/debug.h",
|
||||||
"src/debug/interface-types.h",
|
"src/debug/interface-types.h",
|
||||||
"src/debug/liveedit-diff.h",
|
"src/debug/liveedit-diff.h",
|
||||||
@ -4373,7 +4372,6 @@ v8_source_set("v8_base_without_compiler") {
|
|||||||
"src/debug/debug-scope-iterator.cc",
|
"src/debug/debug-scope-iterator.cc",
|
||||||
"src/debug/debug-scopes.cc",
|
"src/debug/debug-scopes.cc",
|
||||||
"src/debug/debug-stack-trace-iterator.cc",
|
"src/debug/debug-stack-trace-iterator.cc",
|
||||||
"src/debug/debug-type-profile.cc",
|
|
||||||
"src/debug/debug.cc",
|
"src/debug/debug.cc",
|
||||||
"src/debug/liveedit-diff.cc",
|
"src/debug/liveedit-diff.cc",
|
||||||
"src/debug/liveedit.cc",
|
"src/debug/liveedit.cc",
|
||||||
|
@ -946,34 +946,6 @@
|
|||||||
{ "name": "url", "type": "string", "description": "JavaScript script name or url." },
|
{ "name": "url", "type": "string", "description": "JavaScript script name or url." },
|
||||||
{ "name": "functions", "type": "array", "items": { "$ref": "FunctionCoverage" }, "description": "Functions contained in the script that has coverage data." }
|
{ "name": "functions", "type": "array", "items": { "$ref": "FunctionCoverage" }, "description": "Functions contained in the script that has coverage data." }
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{ "id": "TypeObject",
|
|
||||||
"type": "object",
|
|
||||||
"description": "Describes a type collected during runtime.",
|
|
||||||
"properties": [
|
|
||||||
{ "name": "name", "type": "string", "description": "Name of a type collected with type profiling." }
|
|
||||||
],
|
|
||||||
"experimental": true
|
|
||||||
},
|
|
||||||
{ "id": "TypeProfileEntry",
|
|
||||||
"type": "object",
|
|
||||||
"description": "Source offset and types for a parameter or return value.",
|
|
||||||
"properties": [
|
|
||||||
{ "name": "offset", "type": "integer", "description": "Source offset of the parameter or end of function for return values." },
|
|
||||||
{ "name": "types", "type": "array", "items": {"$ref": "TypeObject"}, "description": "The types for this parameter or return value."}
|
|
||||||
],
|
|
||||||
"experimental": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "ScriptTypeProfile",
|
|
||||||
"type": "object",
|
|
||||||
"description": "Type profile data collected during runtime for a JavaScript script.",
|
|
||||||
"properties": [
|
|
||||||
{ "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "JavaScript script id." },
|
|
||||||
{ "name": "url", "type": "string", "description": "JavaScript script name or url." },
|
|
||||||
{ "name": "entries", "type": "array", "items": { "$ref": "TypeProfileEntry" }, "description": "Type profile entries for parameters and return values of the functions in the script." }
|
|
||||||
],
|
|
||||||
"experimental": true
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"commands": [
|
"commands": [
|
||||||
@ -1024,24 +996,6 @@
|
|||||||
{ "name": "result", "type": "array", "items": { "$ref": "ScriptCoverage" }, "description": "Coverage data for the current isolate." }
|
{ "name": "result", "type": "array", "items": { "$ref": "ScriptCoverage" }, "description": "Coverage data for the current isolate." }
|
||||||
],
|
],
|
||||||
"description": "Collect coverage data for the current isolate. The coverage data may be incomplete due to garbage collection."
|
"description": "Collect coverage data for the current isolate. The coverage data may be incomplete due to garbage collection."
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "startTypeProfile",
|
|
||||||
"description": "Enable type profile.",
|
|
||||||
"experimental": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "stopTypeProfile",
|
|
||||||
"description": "Disable type profile. Disabling releases type profile data collected so far.",
|
|
||||||
"experimental": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "takeTypeProfile",
|
|
||||||
"returns": [
|
|
||||||
{ "name": "result", "type": "array", "items": { "$ref": "ScriptTypeProfile" }, "description": "Type profile for all scripts since startTypeProfile() was turned on." }
|
|
||||||
],
|
|
||||||
"description": "Collect type profile.",
|
|
||||||
"experimental": true
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"events": [
|
"events": [
|
||||||
|
@ -918,30 +918,6 @@ domain Profiler
|
|||||||
# Functions contained in the script that has coverage data.
|
# Functions contained in the script that has coverage data.
|
||||||
array of FunctionCoverage functions
|
array of FunctionCoverage functions
|
||||||
|
|
||||||
# Describes a type collected during runtime.
|
|
||||||
experimental type TypeObject extends object
|
|
||||||
properties
|
|
||||||
# Name of a type collected with type profiling.
|
|
||||||
string name
|
|
||||||
|
|
||||||
# Source offset and types for a parameter or return value.
|
|
||||||
experimental type TypeProfileEntry extends object
|
|
||||||
properties
|
|
||||||
# Source offset of the parameter or end of function for return values.
|
|
||||||
integer offset
|
|
||||||
# The types for this parameter or return value.
|
|
||||||
array of TypeObject types
|
|
||||||
|
|
||||||
# Type profile data collected during runtime for a JavaScript script.
|
|
||||||
experimental type ScriptTypeProfile extends object
|
|
||||||
properties
|
|
||||||
# JavaScript script id.
|
|
||||||
Runtime.ScriptId scriptId
|
|
||||||
# JavaScript script name or url.
|
|
||||||
string url
|
|
||||||
# Type profile entries for parameters and return values of the functions in the script.
|
|
||||||
array of TypeProfileEntry entries
|
|
||||||
|
|
||||||
command disable
|
command disable
|
||||||
|
|
||||||
command enable
|
command enable
|
||||||
@ -976,9 +952,6 @@ domain Profiler
|
|||||||
# Monotonically increasing time (in seconds) when the coverage update was taken in the backend.
|
# Monotonically increasing time (in seconds) when the coverage update was taken in the backend.
|
||||||
number timestamp
|
number timestamp
|
||||||
|
|
||||||
# Enable type profile.
|
|
||||||
experimental command startTypeProfile
|
|
||||||
|
|
||||||
command stop
|
command stop
|
||||||
returns
|
returns
|
||||||
# Recorded profile.
|
# Recorded profile.
|
||||||
@ -988,9 +961,6 @@ domain Profiler
|
|||||||
# executing optimized code.
|
# executing optimized code.
|
||||||
command stopPreciseCoverage
|
command stopPreciseCoverage
|
||||||
|
|
||||||
# Disable type profile. Disabling releases type profile data collected so far.
|
|
||||||
experimental command stopTypeProfile
|
|
||||||
|
|
||||||
# Collect coverage data for the current isolate, and resets execution counters. Precise code
|
# Collect coverage data for the current isolate, and resets execution counters. Precise code
|
||||||
# coverage needs to have started.
|
# coverage needs to have started.
|
||||||
command takePreciseCoverage
|
command takePreciseCoverage
|
||||||
@ -1000,12 +970,6 @@ domain Profiler
|
|||||||
# Monotonically increasing time (in seconds) when the coverage update was taken in the backend.
|
# Monotonically increasing time (in seconds) when the coverage update was taken in the backend.
|
||||||
number timestamp
|
number timestamp
|
||||||
|
|
||||||
# Collect type profile.
|
|
||||||
experimental command takeTypeProfile
|
|
||||||
returns
|
|
||||||
# Type profile for all scripts since startTypeProfile() was turned on.
|
|
||||||
array of ScriptTypeProfile result
|
|
||||||
|
|
||||||
event consoleProfileFinished
|
event consoleProfileFinished
|
||||||
parameters
|
parameters
|
||||||
string id
|
string id
|
||||||
|
@ -967,14 +967,6 @@ void BaselineCompiler::VisitDefineKeyedOwnPropertyInLiteral() {
|
|||||||
IndexAsTagged(3)); // slot
|
IndexAsTagged(3)); // slot
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaselineCompiler::VisitCollectTypeProfile() {
|
|
||||||
SaveAccumulatorScope accumulator_scope(&basm_);
|
|
||||||
CallRuntime(Runtime::kCollectTypeProfile,
|
|
||||||
IntAsSmi(0), // position
|
|
||||||
kInterpreterAccumulatorRegister, // value
|
|
||||||
FeedbackVector()); // feedback vector
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaselineCompiler::VisitAdd() {
|
void BaselineCompiler::VisitAdd() {
|
||||||
CallBuiltin<Builtin::kAdd_Baseline>(
|
CallBuiltin<Builtin::kAdd_Baseline>(
|
||||||
RegisterOperand(0), kInterpreterAccumulatorRegister, Index(1));
|
RegisterOperand(0), kInterpreterAccumulatorRegister, Index(1));
|
||||||
|
@ -3282,8 +3282,6 @@ MaybeHandle<SharedFunctionInfo> CompileScriptOnMainThread(
|
|||||||
if (!maybe_script.ToHandle(&script)) {
|
if (!maybe_script.ToHandle(&script)) {
|
||||||
script = NewScript(isolate, &parse_info, source, script_details, natives);
|
script = NewScript(isolate, &parse_info, source, script_details, natives);
|
||||||
}
|
}
|
||||||
DCHECK_IMPLIES(parse_info.flags().collect_type_profile(),
|
|
||||||
script->IsUserJavaScript());
|
|
||||||
DCHECK_EQ(parse_info.flags().is_repl_mode(), script->is_repl_mode());
|
DCHECK_EQ(parse_info.flags().is_repl_mode(), script->is_repl_mode());
|
||||||
|
|
||||||
return Compiler::CompileToplevel(&parse_info, script, isolate,
|
return Compiler::CompileToplevel(&parse_info, script, isolate,
|
||||||
|
@ -1672,20 +1672,6 @@ void BytecodeGraphBuilder::VisitDefineKeyedOwnPropertyInLiteral() {
|
|||||||
environment()->RecordAfterState(node, Environment::kAttachFrameState);
|
environment()->RecordAfterState(node, Environment::kAttachFrameState);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BytecodeGraphBuilder::VisitCollectTypeProfile() {
|
|
||||||
PrepareEagerCheckpoint();
|
|
||||||
|
|
||||||
Node* position =
|
|
||||||
jsgraph()->Constant(bytecode_iterator().GetImmediateOperand(0));
|
|
||||||
Node* value = environment()->LookupAccumulator();
|
|
||||||
Node* vector = jsgraph()->Constant(feedback_vector());
|
|
||||||
|
|
||||||
const Operator* op = javascript()->CallRuntime(Runtime::kCollectTypeProfile);
|
|
||||||
|
|
||||||
Node* node = NewNode(op, position, value, vector);
|
|
||||||
environment()->RecordAfterState(node, Environment::kAttachFrameState);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BytecodeGraphBuilder::VisitLdaContextSlot() {
|
void BytecodeGraphBuilder::VisitLdaContextSlot() {
|
||||||
const Operator* op = javascript()->LoadContext(
|
const Operator* op = javascript()->LoadContext(
|
||||||
bytecode_iterator().GetUnsignedImmediateOperand(2),
|
bytecode_iterator().GetUnsignedImmediateOperand(2),
|
||||||
|
@ -605,9 +605,8 @@ std::unique_ptr<Coverage> Coverage::CollectPrecise(Isolate* isolate) {
|
|||||||
DCHECK(!isolate->is_best_effort_code_coverage());
|
DCHECK(!isolate->is_best_effort_code_coverage());
|
||||||
std::unique_ptr<Coverage> result =
|
std::unique_ptr<Coverage> result =
|
||||||
Collect(isolate, isolate->code_coverage_mode());
|
Collect(isolate, isolate->code_coverage_mode());
|
||||||
if (!isolate->is_collecting_type_profile() &&
|
if (isolate->is_precise_binary_code_coverage() ||
|
||||||
(isolate->is_precise_binary_code_coverage() ||
|
isolate->is_block_binary_code_coverage()) {
|
||||||
isolate->is_block_binary_code_coverage())) {
|
|
||||||
// We do not have to hold onto feedback vectors for invocations we already
|
// We do not have to hold onto feedback vectors for invocations we already
|
||||||
// reported. So we can reset the list.
|
// reported. So we can reset the list.
|
||||||
isolate->SetFeedbackVectorsForProfilingTools(
|
isolate->SetFeedbackVectorsForProfilingTools(
|
||||||
@ -766,10 +765,8 @@ void Coverage::SelectMode(Isolate* isolate, debug::CoverageMode mode) {
|
|||||||
// following coverage recording (without reloads) will be at function
|
// following coverage recording (without reloads) will be at function
|
||||||
// granularity.
|
// granularity.
|
||||||
isolate->debug()->RemoveAllCoverageInfos();
|
isolate->debug()->RemoveAllCoverageInfos();
|
||||||
if (!isolate->is_collecting_type_profile()) {
|
isolate->SetFeedbackVectorsForProfilingTools(
|
||||||
isolate->SetFeedbackVectorsForProfilingTools(
|
ReadOnlyRoots(isolate).undefined_value());
|
||||||
ReadOnlyRoots(isolate).undefined_value());
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case debug::CoverageMode::kBlockBinary:
|
case debug::CoverageMode::kBlockBinary:
|
||||||
case debug::CoverageMode::kBlockCount:
|
case debug::CoverageMode::kBlockCount:
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
#include "src/debug/debug-evaluate.h"
|
#include "src/debug/debug-evaluate.h"
|
||||||
#include "src/debug/debug-property-iterator.h"
|
#include "src/debug/debug-property-iterator.h"
|
||||||
#include "src/debug/debug-stack-trace-iterator.h"
|
#include "src/debug/debug-stack-trace-iterator.h"
|
||||||
#include "src/debug/debug-type-profile.h"
|
|
||||||
#include "src/debug/debug.h"
|
#include "src/debug/debug.h"
|
||||||
#include "src/execution/vm-state-inl.h"
|
#include "src/execution/vm-state-inl.h"
|
||||||
#include "src/heap/heap.h"
|
#include "src/heap/heap.h"
|
||||||
@ -1317,48 +1316,6 @@ void Coverage::SelectMode(Isolate* isolate, CoverageMode mode) {
|
|||||||
i::Coverage::SelectMode(reinterpret_cast<i::Isolate*>(isolate), mode);
|
i::Coverage::SelectMode(reinterpret_cast<i::Isolate*>(isolate), mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
int TypeProfile::Entry::SourcePosition() const { return entry_->position; }
|
|
||||||
|
|
||||||
std::vector<MaybeLocal<String>> TypeProfile::Entry::Types() const {
|
|
||||||
std::vector<MaybeLocal<String>> result;
|
|
||||||
for (const internal::Handle<internal::String>& type : entry_->types) {
|
|
||||||
result.emplace_back(ToApiHandle<String>(type));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeProfile::ScriptData::ScriptData(
|
|
||||||
size_t index, std::shared_ptr<i::TypeProfile> type_profile)
|
|
||||||
: script_(&type_profile->at(index)),
|
|
||||||
type_profile_(std::move(type_profile)) {}
|
|
||||||
|
|
||||||
Local<Script> TypeProfile::ScriptData::GetScript() const {
|
|
||||||
return ToApiHandle<Script>(script_->script);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<TypeProfile::Entry> TypeProfile::ScriptData::Entries() const {
|
|
||||||
std::vector<TypeProfile::Entry> result;
|
|
||||||
for (const internal::TypeProfileEntry& entry : script_->entries) {
|
|
||||||
result.push_back(TypeProfile::Entry(&entry, type_profile_));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeProfile TypeProfile::Collect(Isolate* isolate) {
|
|
||||||
return TypeProfile(
|
|
||||||
i::TypeProfile::Collect(reinterpret_cast<i::Isolate*>(isolate)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TypeProfile::SelectMode(Isolate* isolate, TypeProfileMode mode) {
|
|
||||||
i::TypeProfile::SelectMode(reinterpret_cast<i::Isolate*>(isolate), mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t TypeProfile::ScriptCount() const { return type_profile_->size(); }
|
|
||||||
|
|
||||||
TypeProfile::ScriptData TypeProfile::GetScriptData(size_t i) const {
|
|
||||||
return ScriptData(i, type_profile_);
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeLocal<v8::Value> EphemeronTable::Get(v8::Isolate* isolate,
|
MaybeLocal<v8::Value> EphemeronTable::Get(v8::Isolate* isolate,
|
||||||
v8::Local<v8::Value> key) {
|
v8::Local<v8::Value> key) {
|
||||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||||
|
@ -34,13 +34,10 @@ namespace internal {
|
|||||||
struct CoverageBlock;
|
struct CoverageBlock;
|
||||||
struct CoverageFunction;
|
struct CoverageFunction;
|
||||||
struct CoverageScript;
|
struct CoverageScript;
|
||||||
struct TypeProfileEntry;
|
|
||||||
struct TypeProfileScript;
|
|
||||||
class Coverage;
|
class Coverage;
|
||||||
class DisableBreak;
|
class DisableBreak;
|
||||||
class PostponeInterruptsScope;
|
class PostponeInterruptsScope;
|
||||||
class Script;
|
class Script;
|
||||||
class TypeProfile;
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
namespace debug {
|
namespace debug {
|
||||||
@ -438,64 +435,6 @@ class V8_EXPORT_PRIVATE Coverage {
|
|||||||
std::shared_ptr<i::Coverage> coverage_;
|
std::shared_ptr<i::Coverage> coverage_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Provide API layer between inspector and type profile.
|
|
||||||
*/
|
|
||||||
class V8_EXPORT_PRIVATE TypeProfile {
|
|
||||||
public:
|
|
||||||
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(TypeProfile);
|
|
||||||
|
|
||||||
class ScriptData; // Forward declaration.
|
|
||||||
|
|
||||||
class V8_EXPORT_PRIVATE Entry {
|
|
||||||
public:
|
|
||||||
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(Entry);
|
|
||||||
|
|
||||||
int SourcePosition() const;
|
|
||||||
std::vector<MaybeLocal<String>> Types() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
explicit Entry(const i::TypeProfileEntry* entry,
|
|
||||||
std::shared_ptr<i::TypeProfile> type_profile)
|
|
||||||
: entry_(entry), type_profile_(std::move(type_profile)) {}
|
|
||||||
|
|
||||||
const i::TypeProfileEntry* entry_;
|
|
||||||
std::shared_ptr<i::TypeProfile> type_profile_;
|
|
||||||
|
|
||||||
friend class v8::debug::TypeProfile::ScriptData;
|
|
||||||
};
|
|
||||||
|
|
||||||
class V8_EXPORT_PRIVATE ScriptData {
|
|
||||||
public:
|
|
||||||
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(ScriptData);
|
|
||||||
|
|
||||||
Local<debug::Script> GetScript() const;
|
|
||||||
std::vector<Entry> Entries() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
explicit ScriptData(size_t index,
|
|
||||||
std::shared_ptr<i::TypeProfile> type_profile);
|
|
||||||
|
|
||||||
i::TypeProfileScript* script_;
|
|
||||||
std::shared_ptr<i::TypeProfile> type_profile_;
|
|
||||||
|
|
||||||
friend class v8::debug::TypeProfile;
|
|
||||||
};
|
|
||||||
|
|
||||||
static TypeProfile Collect(Isolate* isolate);
|
|
||||||
|
|
||||||
static void SelectMode(Isolate* isolate, TypeProfileMode mode);
|
|
||||||
|
|
||||||
size_t ScriptCount() const;
|
|
||||||
ScriptData GetScriptData(size_t i) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
explicit TypeProfile(std::shared_ptr<i::TypeProfile> type_profile)
|
|
||||||
: type_profile_(std::move(type_profile)) {}
|
|
||||||
|
|
||||||
std::shared_ptr<i::TypeProfile> type_profile_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class V8_EXPORT_PRIVATE ScopeIterator {
|
class V8_EXPORT_PRIVATE ScopeIterator {
|
||||||
public:
|
public:
|
||||||
static std::unique_ptr<ScopeIterator> CreateForFunction(
|
static std::unique_ptr<ScopeIterator> CreateForFunction(
|
||||||
|
@ -1,121 +0,0 @@
|
|||||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
#include "src/debug/debug-type-profile.h"
|
|
||||||
|
|
||||||
#include "src/execution/isolate.h"
|
|
||||||
#include "src/objects/feedback-vector.h"
|
|
||||||
#include "src/objects/objects-inl.h"
|
|
||||||
#include "src/objects/objects.h"
|
|
||||||
|
|
||||||
namespace v8 {
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
std::unique_ptr<TypeProfile> TypeProfile::Collect(Isolate* isolate) {
|
|
||||||
std::unique_ptr<TypeProfile> result(new TypeProfile());
|
|
||||||
|
|
||||||
// Feedback vectors are already listed to prevent losing them to GC.
|
|
||||||
DCHECK(isolate->factory()
|
|
||||||
->feedback_vectors_for_profiling_tools()
|
|
||||||
->IsArrayList());
|
|
||||||
Handle<ArrayList> list = Handle<ArrayList>::cast(
|
|
||||||
isolate->factory()->feedback_vectors_for_profiling_tools());
|
|
||||||
|
|
||||||
Script::Iterator scripts(isolate);
|
|
||||||
|
|
||||||
for (Script script = scripts.Next(); !script.is_null();
|
|
||||||
script = scripts.Next()) {
|
|
||||||
if (!script.IsUserJavaScript()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Script> script_handle(script, isolate);
|
|
||||||
|
|
||||||
TypeProfileScript type_profile_script(script_handle);
|
|
||||||
std::vector<TypeProfileEntry>* entries = &type_profile_script.entries;
|
|
||||||
|
|
||||||
// TODO(franzih): Sort the vectors by script first instead of iterating
|
|
||||||
// the list multiple times.
|
|
||||||
for (int i = 0; i < list->Length(); i++) {
|
|
||||||
FeedbackVector vector = FeedbackVector::cast(list->Get(i));
|
|
||||||
SharedFunctionInfo info = vector.shared_function_info();
|
|
||||||
DCHECK(info.IsSubjectToDebugging());
|
|
||||||
|
|
||||||
// Match vectors with script.
|
|
||||||
if (script != info.script()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!info.HasFeedbackMetadata() || info.feedback_metadata().is_empty() ||
|
|
||||||
!info.feedback_metadata().HasTypeProfileSlot()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
FeedbackSlot slot = vector.GetTypeProfileSlot();
|
|
||||||
FeedbackNexus nexus(vector, slot);
|
|
||||||
std::vector<int> source_positions = nexus.GetSourcePositions();
|
|
||||||
for (int position : source_positions) {
|
|
||||||
DCHECK_GE(position, 0);
|
|
||||||
entries->emplace_back(position, nexus.GetTypesForSourcePositions(
|
|
||||||
static_cast<uint32_t>(position)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Releases type profile data collected so far.
|
|
||||||
nexus.ResetTypeProfile();
|
|
||||||
}
|
|
||||||
if (!entries->empty()) {
|
|
||||||
result->emplace_back(type_profile_script);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TypeProfile::SelectMode(Isolate* isolate, debug::TypeProfileMode mode) {
|
|
||||||
if (mode != isolate->type_profile_mode()) {
|
|
||||||
// Changing the type profile mode can change the bytecode that would be
|
|
||||||
// generated for a function, which can interfere with lazy source positions,
|
|
||||||
// so just force source position collection whenever there's such a change.
|
|
||||||
isolate->CollectSourcePositionsForAllBytecodeArrays();
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleScope handle_scope(isolate);
|
|
||||||
|
|
||||||
if (mode == debug::TypeProfileMode::kNone) {
|
|
||||||
if (!isolate->factory()
|
|
||||||
->feedback_vectors_for_profiling_tools()
|
|
||||||
->IsUndefined(isolate)) {
|
|
||||||
// Release type profile data collected so far.
|
|
||||||
|
|
||||||
// Feedback vectors are already listed to prevent losing them to GC.
|
|
||||||
DCHECK(isolate->factory()
|
|
||||||
->feedback_vectors_for_profiling_tools()
|
|
||||||
->IsArrayList());
|
|
||||||
Handle<ArrayList> list = Handle<ArrayList>::cast(
|
|
||||||
isolate->factory()->feedback_vectors_for_profiling_tools());
|
|
||||||
|
|
||||||
for (int i = 0; i < list->Length(); i++) {
|
|
||||||
FeedbackVector vector = FeedbackVector::cast(list->Get(i));
|
|
||||||
SharedFunctionInfo info = vector.shared_function_info();
|
|
||||||
DCHECK(info.IsSubjectToDebugging());
|
|
||||||
if (info.feedback_metadata().HasTypeProfileSlot()) {
|
|
||||||
FeedbackSlot slot = vector.GetTypeProfileSlot();
|
|
||||||
FeedbackNexus nexus(vector, slot);
|
|
||||||
nexus.ResetTypeProfile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the feedback vectors from the list if they're not used by code
|
|
||||||
// coverage.
|
|
||||||
if (isolate->is_best_effort_code_coverage()) {
|
|
||||||
isolate->SetFeedbackVectorsForProfilingTools(
|
|
||||||
ReadOnlyRoots(isolate).undefined_value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DCHECK_EQ(debug::TypeProfileMode::kCollect, mode);
|
|
||||||
isolate->MaybeInitializeVectorListFromHeap();
|
|
||||||
}
|
|
||||||
isolate->set_type_profile_mode(mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace v8
|
|
@ -1,46 +0,0 @@
|
|||||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
#ifndef V8_DEBUG_DEBUG_TYPE_PROFILE_H_
|
|
||||||
#define V8_DEBUG_DEBUG_TYPE_PROFILE_H_
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "src/debug/debug-interface.h"
|
|
||||||
#include "src/handles/handles.h"
|
|
||||||
|
|
||||||
namespace v8 {
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
// Forward declaration.
|
|
||||||
class Isolate;
|
|
||||||
|
|
||||||
struct TypeProfileEntry {
|
|
||||||
explicit TypeProfileEntry(
|
|
||||||
int pos, std::vector<v8::internal::Handle<internal::String>> t)
|
|
||||||
: position(pos), types(std::move(t)) {}
|
|
||||||
int position;
|
|
||||||
std::vector<v8::internal::Handle<internal::String>> types;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TypeProfileScript {
|
|
||||||
explicit TypeProfileScript(Handle<Script> s) : script(s) {}
|
|
||||||
Handle<Script> script;
|
|
||||||
std::vector<TypeProfileEntry> entries;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TypeProfile : public std::vector<TypeProfileScript> {
|
|
||||||
public:
|
|
||||||
static std::unique_ptr<TypeProfile> Collect(Isolate* isolate);
|
|
||||||
static void SelectMode(Isolate* isolate, debug::TypeProfileMode mode);
|
|
||||||
|
|
||||||
private:
|
|
||||||
TypeProfile() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace v8
|
|
||||||
|
|
||||||
#endif // V8_DEBUG_DEBUG_TYPE_PROFILE_H_
|
|
@ -78,11 +78,6 @@ enum class CoverageMode {
|
|||||||
kBlockBinary,
|
kBlockBinary,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class TypeProfileMode {
|
|
||||||
kNone,
|
|
||||||
kCollect,
|
|
||||||
};
|
|
||||||
|
|
||||||
class V8_EXPORT_PRIVATE BreakLocation : public Location {
|
class V8_EXPORT_PRIVATE BreakLocation : public Location {
|
||||||
public:
|
public:
|
||||||
BreakLocation(int line_number, int column_number, BreakLocationType type)
|
BreakLocation(int line_number, int column_number, BreakLocationType type)
|
||||||
|
@ -1333,7 +1333,6 @@ void FeedbackNexus::Print(std::ostream& os) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FeedbackSlotKind::kLiteral:
|
case FeedbackSlotKind::kLiteral:
|
||||||
case FeedbackSlotKind::kTypeProfile:
|
|
||||||
break;
|
break;
|
||||||
case FeedbackSlotKind::kJumpLoop:
|
case FeedbackSlotKind::kJumpLoop:
|
||||||
os << "JumpLoop";
|
os << "JumpLoop";
|
||||||
|
@ -529,7 +529,6 @@ using DebugObjectCache = std::vector<Handle<HeapObject>>;
|
|||||||
V(bool, formatting_stack_trace, false) \
|
V(bool, formatting_stack_trace, false) \
|
||||||
/* Perform side effect checks on function call and API callbacks. */ \
|
/* Perform side effect checks on function call and API callbacks. */ \
|
||||||
V(DebugInfo::ExecutionMode, debug_execution_mode, DebugInfo::kBreakpoints) \
|
V(DebugInfo::ExecutionMode, debug_execution_mode, DebugInfo::kBreakpoints) \
|
||||||
V(debug::TypeProfileMode, type_profile_mode, debug::TypeProfileMode::kNone) \
|
|
||||||
V(bool, disable_bytecode_flushing, false) \
|
V(bool, disable_bytecode_flushing, false) \
|
||||||
V(int, last_console_context_id, 0) \
|
V(int, last_console_context_id, 0) \
|
||||||
V(v8_inspector::V8Inspector*, inspector, nullptr) \
|
V(v8_inspector::V8Inspector*, inspector, nullptr) \
|
||||||
@ -1431,10 +1430,6 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
|
|||||||
return is_precise_count_code_coverage() || is_block_count_code_coverage();
|
return is_precise_count_code_coverage() || is_block_count_code_coverage();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_collecting_type_profile() const {
|
|
||||||
return type_profile_mode() == debug::TypeProfileMode::kCollect;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect feedback vectors with data for code coverage or type profile.
|
// Collect feedback vectors with data for code coverage or type profile.
|
||||||
// Reset the list, when both code coverage and type profile are not
|
// Reset the list, when both code coverage and type profile are not
|
||||||
// needed anymore. This keeps many feedback vectors alive, but code
|
// needed anymore. This keeps many feedback vectors alive, but code
|
||||||
|
@ -60,11 +60,6 @@ int LocalIsolate::GetNextUniqueSharedFunctionInfoId() {
|
|||||||
}
|
}
|
||||||
#endif // V8_SFI_HAS_UNIQUE_ID
|
#endif // V8_SFI_HAS_UNIQUE_ID
|
||||||
|
|
||||||
bool LocalIsolate::is_collecting_type_profile() const {
|
|
||||||
// TODO(leszeks): Figure out if it makes sense to check this asynchronously.
|
|
||||||
return isolate_->is_collecting_type_profile();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used for lazy initialization, based on an assumption that most
|
// Used for lazy initialization, based on an assumption that most
|
||||||
// LocalIsolates won't be used to parse any BigInt literals.
|
// LocalIsolates won't be used to parse any BigInt literals.
|
||||||
void LocalIsolate::InitializeBigIntProcessor() {
|
void LocalIsolate::InitializeBigIntProcessor() {
|
||||||
|
@ -106,8 +106,6 @@ class V8_EXPORT_PRIVATE LocalIsolate final : private HiddenLocalFactory {
|
|||||||
int GetNextUniqueSharedFunctionInfoId();
|
int GetNextUniqueSharedFunctionInfoId();
|
||||||
#endif // V8_SFI_HAS_UNIQUE_ID
|
#endif // V8_SFI_HAS_UNIQUE_ID
|
||||||
|
|
||||||
bool is_collecting_type_profile() const;
|
|
||||||
|
|
||||||
// TODO(cbruni): rename this back to logger() once the V8FileLogger
|
// TODO(cbruni): rename this back to logger() once the V8FileLogger
|
||||||
// refactoring is completed.
|
// refactoring is completed.
|
||||||
LocalLogger* v8_file_logger() const { return logger_.get(); }
|
LocalLogger* v8_file_logger() const { return logger_.get(); }
|
||||||
|
@ -28,7 +28,6 @@ static const char preciseCoverageCallCount[] = "preciseCoverageCallCount";
|
|||||||
static const char preciseCoverageDetailed[] = "preciseCoverageDetailed";
|
static const char preciseCoverageDetailed[] = "preciseCoverageDetailed";
|
||||||
static const char preciseCoverageAllowTriggeredUpdates[] =
|
static const char preciseCoverageAllowTriggeredUpdates[] =
|
||||||
"preciseCoverageAllowTriggeredUpdates";
|
"preciseCoverageAllowTriggeredUpdates";
|
||||||
static const char typeProfileStarted[] = "typeProfileStarted";
|
|
||||||
} // namespace ProfilerAgentState
|
} // namespace ProfilerAgentState
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -450,80 +449,6 @@ Response V8ProfilerAgentImpl::getBestEffortCoverage(
|
|||||||
return coverageToProtocol(m_session->inspector(), coverage, out_result);
|
return coverageToProtocol(m_session->inspector(), coverage, out_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
std::unique_ptr<protocol::Array<protocol::Profiler::ScriptTypeProfile>>
|
|
||||||
typeProfileToProtocol(V8InspectorImpl* inspector,
|
|
||||||
const v8::debug::TypeProfile& type_profile) {
|
|
||||||
auto result = std::make_unique<
|
|
||||||
protocol::Array<protocol::Profiler::ScriptTypeProfile>>();
|
|
||||||
v8::Isolate* isolate = inspector->isolate();
|
|
||||||
for (size_t i = 0; i < type_profile.ScriptCount(); i++) {
|
|
||||||
v8::debug::TypeProfile::ScriptData script_data =
|
|
||||||
type_profile.GetScriptData(i);
|
|
||||||
v8::Local<v8::debug::Script> script = script_data.GetScript();
|
|
||||||
auto entries = std::make_unique<
|
|
||||||
protocol::Array<protocol::Profiler::TypeProfileEntry>>();
|
|
||||||
|
|
||||||
for (const auto& entry : script_data.Entries()) {
|
|
||||||
auto types =
|
|
||||||
std::make_unique<protocol::Array<protocol::Profiler::TypeObject>>();
|
|
||||||
for (const auto& type : entry.Types()) {
|
|
||||||
types->emplace_back(
|
|
||||||
protocol::Profiler::TypeObject::create()
|
|
||||||
.setName(toProtocolString(
|
|
||||||
isolate, type.FromMaybe(v8::Local<v8::String>())))
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
entries->emplace_back(protocol::Profiler::TypeProfileEntry::create()
|
|
||||||
.setOffset(entry.SourcePosition())
|
|
||||||
.setTypes(std::move(types))
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
String16 url;
|
|
||||||
v8::Local<v8::String> name;
|
|
||||||
if (script->SourceURL().ToLocal(&name) && name->Length()) {
|
|
||||||
url = toProtocolString(isolate, name);
|
|
||||||
} else if (script->Name().ToLocal(&name) && name->Length()) {
|
|
||||||
url = resourceNameToUrl(inspector, name);
|
|
||||||
}
|
|
||||||
result->emplace_back(protocol::Profiler::ScriptTypeProfile::create()
|
|
||||||
.setScriptId(String16::fromInteger(script->Id()))
|
|
||||||
.setUrl(url)
|
|
||||||
.setEntries(std::move(entries))
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
Response V8ProfilerAgentImpl::startTypeProfile() {
|
|
||||||
m_state->setBoolean(ProfilerAgentState::typeProfileStarted, true);
|
|
||||||
v8::debug::TypeProfile::SelectMode(m_isolate,
|
|
||||||
v8::debug::TypeProfileMode::kCollect);
|
|
||||||
return Response::Success();
|
|
||||||
}
|
|
||||||
|
|
||||||
Response V8ProfilerAgentImpl::stopTypeProfile() {
|
|
||||||
m_state->setBoolean(ProfilerAgentState::typeProfileStarted, false);
|
|
||||||
v8::debug::TypeProfile::SelectMode(m_isolate,
|
|
||||||
v8::debug::TypeProfileMode::kNone);
|
|
||||||
return Response::Success();
|
|
||||||
}
|
|
||||||
|
|
||||||
Response V8ProfilerAgentImpl::takeTypeProfile(
|
|
||||||
std::unique_ptr<protocol::Array<protocol::Profiler::ScriptTypeProfile>>*
|
|
||||||
out_result) {
|
|
||||||
if (!m_state->booleanProperty(ProfilerAgentState::typeProfileStarted,
|
|
||||||
false)) {
|
|
||||||
return Response::ServerError("Type profile has not been started.");
|
|
||||||
}
|
|
||||||
v8::HandleScope handle_scope(m_isolate);
|
|
||||||
v8::debug::TypeProfile type_profile =
|
|
||||||
v8::debug::TypeProfile::Collect(m_isolate);
|
|
||||||
*out_result = typeProfileToProtocol(m_session->inspector(), type_profile);
|
|
||||||
return Response::Success();
|
|
||||||
}
|
|
||||||
|
|
||||||
String16 V8ProfilerAgentImpl::nextProfileId() {
|
String16 V8ProfilerAgentImpl::nextProfileId() {
|
||||||
return String16::fromInteger(
|
return String16::fromInteger(
|
||||||
v8::base::Relaxed_AtomicIncrement(&s_lastProfileId, 1));
|
v8::base::Relaxed_AtomicIncrement(&s_lastProfileId, 1));
|
||||||
|
@ -53,12 +53,6 @@ class V8ProfilerAgentImpl : public protocol::Profiler::Backend {
|
|||||||
std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>*
|
std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>*
|
||||||
out_result) override;
|
out_result) override;
|
||||||
|
|
||||||
Response startTypeProfile() override;
|
|
||||||
Response stopTypeProfile() override;
|
|
||||||
Response takeTypeProfile(
|
|
||||||
std::unique_ptr<protocol::Array<protocol::Profiler::ScriptTypeProfile>>*
|
|
||||||
out_result) override;
|
|
||||||
|
|
||||||
void consoleProfile(const String16& title);
|
void consoleProfile(const String16& title);
|
||||||
void consoleProfileEnd(const String16& title);
|
void consoleProfileEnd(const String16& title);
|
||||||
|
|
||||||
|
@ -881,11 +881,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::DefineKeyedOwnPropertyInLiteral(
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
BytecodeArrayBuilder& BytecodeArrayBuilder::CollectTypeProfile(int position) {
|
|
||||||
OutputCollectTypeProfile(position);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
BytecodeArrayBuilder& BytecodeArrayBuilder::SetNamedProperty(
|
BytecodeArrayBuilder& BytecodeArrayBuilder::SetNamedProperty(
|
||||||
Register object, size_t name_index, int feedback_slot,
|
Register object, size_t name_index, int feedback_slot,
|
||||||
LanguageMode language_mode) {
|
LanguageMode language_mode) {
|
||||||
|
@ -158,10 +158,6 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final {
|
|||||||
Register object, Register name,
|
Register object, Register name,
|
||||||
DefineKeyedOwnPropertyInLiteralFlags flags, int feedback_slot);
|
DefineKeyedOwnPropertyInLiteralFlags flags, int feedback_slot);
|
||||||
|
|
||||||
// Collect type information for developer tools. The value for which we
|
|
||||||
// record the type is stored in the accumulator.
|
|
||||||
BytecodeArrayBuilder& CollectTypeProfile(int position);
|
|
||||||
|
|
||||||
// Set a property named by a property name, trigger the setters and
|
// Set a property named by a property name, trigger the setters and
|
||||||
// set traps if necessary. The value to be set should be in the
|
// set traps if necessary. The value to be set should be in the
|
||||||
// accumulator.
|
// accumulator.
|
||||||
|
@ -1423,17 +1423,6 @@ void BytecodeGenerator::GenerateBytecodeBody() {
|
|||||||
// Emit tracing call if requested to do so.
|
// Emit tracing call if requested to do so.
|
||||||
if (v8_flags.trace) builder()->CallRuntime(Runtime::kTraceEnter);
|
if (v8_flags.trace) builder()->CallRuntime(Runtime::kTraceEnter);
|
||||||
|
|
||||||
// Emit type profile call.
|
|
||||||
if (info()->flags().collect_type_profile()) {
|
|
||||||
feedback_spec()->AddTypeProfileSlot();
|
|
||||||
int num_parameters = closure_scope()->num_parameters();
|
|
||||||
for (int i = 0; i < num_parameters; i++) {
|
|
||||||
Register parameter(builder()->Parameter(i));
|
|
||||||
builder()->LoadAccumulatorWithRegister(parameter).CollectTypeProfile(
|
|
||||||
closure_scope()->parameter(i)->initializer_position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment the function-scope block coverage counter.
|
// Increment the function-scope block coverage counter.
|
||||||
BuildIncrementBlockCoverageCounterIfEnabled(literal, SourceRangeKind::kBody);
|
BuildIncrementBlockCoverageCounterIfEnabled(literal, SourceRangeKind::kBody);
|
||||||
|
|
||||||
@ -3686,9 +3675,6 @@ void BytecodeGenerator::BuildReturn(int source_position) {
|
|||||||
builder()->StoreAccumulatorInRegister(result).CallRuntime(
|
builder()->StoreAccumulatorInRegister(result).CallRuntime(
|
||||||
Runtime::kTraceExit, result);
|
Runtime::kTraceExit, result);
|
||||||
}
|
}
|
||||||
if (info()->flags().collect_type_profile()) {
|
|
||||||
builder()->CollectTypeProfile(info()->literal()->return_position());
|
|
||||||
}
|
|
||||||
builder()->SetStatementPosition(source_position);
|
builder()->SetStatementPosition(source_position);
|
||||||
builder()->Return();
|
builder()->Return();
|
||||||
}
|
}
|
||||||
|
@ -157,8 +157,6 @@ namespace interpreter {
|
|||||||
V(DefineKeyedOwnPropertyInLiteral, ImplicitRegisterUse::kReadAccumulator, \
|
V(DefineKeyedOwnPropertyInLiteral, ImplicitRegisterUse::kReadAccumulator, \
|
||||||
OperandType::kReg, OperandType::kReg, OperandType::kFlag8, \
|
OperandType::kReg, OperandType::kReg, OperandType::kFlag8, \
|
||||||
OperandType::kIdx) \
|
OperandType::kIdx) \
|
||||||
V(CollectTypeProfile, ImplicitRegisterUse::kReadAccumulator, \
|
|
||||||
OperandType::kImm) \
|
|
||||||
\
|
\
|
||||||
/* Binary Operators */ \
|
/* Binary Operators */ \
|
||||||
V(Add, ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg, \
|
V(Add, ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg, \
|
||||||
|
@ -743,18 +743,6 @@ IGNITION_HANDLER(DefineKeyedOwnPropertyInLiteral, InterpreterAssembler) {
|
|||||||
Dispatch();
|
Dispatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
IGNITION_HANDLER(CollectTypeProfile, InterpreterAssembler) {
|
|
||||||
TNode<Smi> position = BytecodeOperandImmSmi(0);
|
|
||||||
TNode<Object> value = GetAccumulator();
|
|
||||||
|
|
||||||
TNode<HeapObject> feedback_vector = LoadFeedbackVector();
|
|
||||||
TNode<Context> context = GetContext();
|
|
||||||
|
|
||||||
CallRuntime(Runtime::kCollectTypeProfile, context, position, value,
|
|
||||||
feedback_vector);
|
|
||||||
Dispatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
// LdaModuleVariable <cell_index> <depth>
|
// LdaModuleVariable <cell_index> <depth>
|
||||||
//
|
//
|
||||||
// Load the contents of a module variable into the accumulator. The variable is
|
// Load the contents of a module variable into the accumulator. The variable is
|
||||||
|
@ -1895,14 +1895,6 @@ void MaglevGraphBuilder::VisitDefineKeyedOwnPropertyInLiteral() {
|
|||||||
{object, name, value, flags, feedback_vector, slot}));
|
{object, name, value, flags, feedback_vector, slot}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaglevGraphBuilder::VisitCollectTypeProfile() {
|
|
||||||
ValueNode* position = GetSmiConstant(GetFlag8Operand(0));
|
|
||||||
ValueNode* value = GetAccumulatorTagged();
|
|
||||||
ValueNode* feedback_vector = GetConstant(feedback());
|
|
||||||
SetAccumulator(BuildCallRuntime(Runtime::kCollectTypeProfile,
|
|
||||||
{position, value, feedback_vector}));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaglevGraphBuilder::VisitAdd() { VisitBinaryOperation<Operation::kAdd>(); }
|
void MaglevGraphBuilder::VisitAdd() { VisitBinaryOperation<Operation::kAdd>(); }
|
||||||
void MaglevGraphBuilder::VisitSub() {
|
void MaglevGraphBuilder::VisitSub() {
|
||||||
VisitBinaryOperation<Operation::kSubtract>();
|
VisitBinaryOperation<Operation::kSubtract>();
|
||||||
|
@ -70,7 +70,6 @@ int FeedbackMetadata::GetSlotSize(FeedbackSlotKind kind) {
|
|||||||
case FeedbackSlotKind::kCompareOp:
|
case FeedbackSlotKind::kCompareOp:
|
||||||
case FeedbackSlotKind::kBinaryOp:
|
case FeedbackSlotKind::kBinaryOp:
|
||||||
case FeedbackSlotKind::kLiteral:
|
case FeedbackSlotKind::kLiteral:
|
||||||
case FeedbackSlotKind::kTypeProfile:
|
|
||||||
case FeedbackSlotKind::kJumpLoop:
|
case FeedbackSlotKind::kJumpLoop:
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -31,20 +31,6 @@ FeedbackSlot FeedbackVectorSpec::AddSlot(FeedbackSlotKind kind) {
|
|||||||
return FeedbackSlot(slot);
|
return FeedbackSlot(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
FeedbackSlot FeedbackVectorSpec::AddTypeProfileSlot() {
|
|
||||||
FeedbackSlot slot = AddSlot(FeedbackSlotKind::kTypeProfile);
|
|
||||||
CHECK_EQ(FeedbackVectorSpec::kTypeProfileSlotIndex,
|
|
||||||
FeedbackVector::GetIndex(slot));
|
|
||||||
return slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FeedbackVectorSpec::HasTypeProfileSlot() const {
|
|
||||||
FeedbackSlot slot =
|
|
||||||
FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
|
|
||||||
if (slot_count() <= slot.ToInt()) return false;
|
|
||||||
return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsPropertyNameFeedback(MaybeObject feedback) {
|
static bool IsPropertyNameFeedback(MaybeObject feedback) {
|
||||||
HeapObject heap_object;
|
HeapObject heap_object;
|
||||||
if (!feedback->GetHeapObjectIfStrong(&heap_object)) return false;
|
if (!feedback->GetHeapObjectIfStrong(&heap_object)) return false;
|
||||||
@ -184,8 +170,6 @@ const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
|
|||||||
return "DefineKeyedOwnPropertyInLiteral";
|
return "DefineKeyedOwnPropertyInLiteral";
|
||||||
case FeedbackSlotKind::kLiteral:
|
case FeedbackSlotKind::kLiteral:
|
||||||
return "Literal";
|
return "Literal";
|
||||||
case FeedbackSlotKind::kTypeProfile:
|
|
||||||
return "TypeProfile";
|
|
||||||
case FeedbackSlotKind::kForIn:
|
case FeedbackSlotKind::kForIn:
|
||||||
return "ForIn";
|
return "ForIn";
|
||||||
case FeedbackSlotKind::kInstanceOf:
|
case FeedbackSlotKind::kInstanceOf:
|
||||||
@ -197,13 +181,6 @@ const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FeedbackMetadata::HasTypeProfileSlot() const {
|
|
||||||
FeedbackSlot slot =
|
|
||||||
FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
|
|
||||||
return slot.ToInt() < slot_count() &&
|
|
||||||
GetKind(slot) == FeedbackSlotKind::kTypeProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
|
FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
|
||||||
DCHECK(!is_empty());
|
DCHECK(!is_empty());
|
||||||
return metadata().GetKind(slot);
|
return metadata().GetKind(slot);
|
||||||
@ -215,14 +192,6 @@ FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot,
|
|||||||
return metadata(tag).GetKind(slot);
|
return metadata(tag).GetKind(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
FeedbackSlot FeedbackVector::GetTypeProfileSlot() const {
|
|
||||||
DCHECK(metadata().HasTypeProfileSlot());
|
|
||||||
FeedbackSlot slot =
|
|
||||||
FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
|
|
||||||
DCHECK_EQ(FeedbackSlotKind::kTypeProfile, GetKind(slot));
|
|
||||||
return slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
Handle<ClosureFeedbackCellArray> ClosureFeedbackCellArray::New(
|
Handle<ClosureFeedbackCellArray> ClosureFeedbackCellArray::New(
|
||||||
Isolate* isolate, Handle<SharedFunctionInfo> shared) {
|
Isolate* isolate, Handle<SharedFunctionInfo> shared) {
|
||||||
@ -310,7 +279,6 @@ Handle<FeedbackVector> FeedbackVector::New(
|
|||||||
case FeedbackSlotKind::kSetKeyedStrict:
|
case FeedbackSlotKind::kSetKeyedStrict:
|
||||||
case FeedbackSlotKind::kStoreInArrayLiteral:
|
case FeedbackSlotKind::kStoreInArrayLiteral:
|
||||||
case FeedbackSlotKind::kDefineKeyedOwnPropertyInLiteral:
|
case FeedbackSlotKind::kDefineKeyedOwnPropertyInLiteral:
|
||||||
case FeedbackSlotKind::kTypeProfile:
|
|
||||||
case FeedbackSlotKind::kInstanceOf:
|
case FeedbackSlotKind::kInstanceOf:
|
||||||
vector->Set(slot, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
|
vector->Set(slot, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
|
||||||
break;
|
break;
|
||||||
@ -325,8 +293,7 @@ Handle<FeedbackVector> FeedbackVector::New(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector);
|
Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector);
|
||||||
if (!isolate->is_best_effort_code_coverage() ||
|
if (!isolate->is_best_effort_code_coverage()) {
|
||||||
isolate->is_collecting_type_profile()) {
|
|
||||||
AddToVectorsForProfilingTools(isolate, result);
|
AddToVectorsForProfilingTools(isolate, result);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -372,8 +339,7 @@ Handle<FeedbackVector> FeedbackVector::NewWithOneCompareSlotForTesting(
|
|||||||
// static
|
// static
|
||||||
void FeedbackVector::AddToVectorsForProfilingTools(
|
void FeedbackVector::AddToVectorsForProfilingTools(
|
||||||
Isolate* isolate, Handle<FeedbackVector> vector) {
|
Isolate* isolate, Handle<FeedbackVector> vector) {
|
||||||
DCHECK(!isolate->is_best_effort_code_coverage() ||
|
DCHECK(!isolate->is_best_effort_code_coverage());
|
||||||
isolate->is_collecting_type_profile());
|
|
||||||
if (!vector->shared_function_info().IsSubjectToDebugging()) return;
|
if (!vector->shared_function_info().IsSubjectToDebugging()) return;
|
||||||
Handle<ArrayList> list = Handle<ArrayList>::cast(
|
Handle<ArrayList> list = Handle<ArrayList>::cast(
|
||||||
isolate->factory()->feedback_vectors_for_profiling_tools());
|
isolate->factory()->feedback_vectors_for_profiling_tools());
|
||||||
@ -613,16 +579,6 @@ bool FeedbackNexus::Clear(ClearBehavior behavior) {
|
|||||||
bool feedback_updated = false;
|
bool feedback_updated = false;
|
||||||
|
|
||||||
switch (kind()) {
|
switch (kind()) {
|
||||||
case FeedbackSlotKind::kTypeProfile:
|
|
||||||
if (V8_LIKELY(behavior == ClearBehavior::kDefault)) {
|
|
||||||
// We don't clear these kinds ever.
|
|
||||||
} else if (!IsCleared()) {
|
|
||||||
DCHECK_EQ(behavior, ClearBehavior::kClearAll);
|
|
||||||
SetFeedback(UninitializedSentinel(), SKIP_WRITE_BARRIER);
|
|
||||||
feedback_updated = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FeedbackSlotKind::kCompareOp:
|
case FeedbackSlotKind::kCompareOp:
|
||||||
case FeedbackSlotKind::kForIn:
|
case FeedbackSlotKind::kForIn:
|
||||||
case FeedbackSlotKind::kBinaryOp:
|
case FeedbackSlotKind::kBinaryOp:
|
||||||
@ -849,12 +805,6 @@ InlineCacheState FeedbackNexus::ic_state() const {
|
|||||||
|
|
||||||
return InlineCacheState::MEGAMORPHIC;
|
return InlineCacheState::MEGAMORPHIC;
|
||||||
}
|
}
|
||||||
case FeedbackSlotKind::kTypeProfile: {
|
|
||||||
if (feedback == UninitializedSentinel()) {
|
|
||||||
return InlineCacheState::UNINITIALIZED;
|
|
||||||
}
|
|
||||||
return InlineCacheState::MONOMORPHIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
case FeedbackSlotKind::kCloneObject: {
|
case FeedbackSlotKind::kCloneObject: {
|
||||||
if (feedback == UninitializedSentinel()) {
|
if (feedback == UninitializedSentinel()) {
|
||||||
@ -1355,120 +1305,6 @@ MaybeHandle<JSObject> FeedbackNexus::GetConstructorFeedback() const {
|
|||||||
return MaybeHandle<JSObject>();
|
return MaybeHandle<JSObject>();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
bool InList(Handle<ArrayList> types, Handle<String> type) {
|
|
||||||
for (int i = 0; i < types->Length(); i++) {
|
|
||||||
Object obj = types->Get(i);
|
|
||||||
if (String::cast(obj).Equals(*type)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void FeedbackNexus::Collect(Handle<String> type, int position) {
|
|
||||||
DCHECK(IsTypeProfileKind(kind()));
|
|
||||||
DCHECK_GE(position, 0);
|
|
||||||
DCHECK(config()->can_write());
|
|
||||||
Isolate* isolate = GetIsolate();
|
|
||||||
|
|
||||||
MaybeObject const feedback = GetFeedback();
|
|
||||||
|
|
||||||
// Map source position to collection of types
|
|
||||||
Handle<SimpleNumberDictionary> types;
|
|
||||||
|
|
||||||
if (feedback == UninitializedSentinel()) {
|
|
||||||
types = SimpleNumberDictionary::New(isolate, 1);
|
|
||||||
} else {
|
|
||||||
types = handle(
|
|
||||||
SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
|
|
||||||
isolate);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<ArrayList> position_specific_types;
|
|
||||||
|
|
||||||
InternalIndex entry = types->FindEntry(isolate, position);
|
|
||||||
if (entry.is_not_found()) {
|
|
||||||
position_specific_types = ArrayList::New(isolate, 1);
|
|
||||||
types = SimpleNumberDictionary::Set(
|
|
||||||
isolate, types, position,
|
|
||||||
ArrayList::Add(isolate, position_specific_types, type));
|
|
||||||
} else {
|
|
||||||
DCHECK(types->ValueAt(entry).IsArrayList());
|
|
||||||
position_specific_types =
|
|
||||||
handle(ArrayList::cast(types->ValueAt(entry)), isolate);
|
|
||||||
if (!InList(position_specific_types, type)) { // Add type
|
|
||||||
types = SimpleNumberDictionary::Set(
|
|
||||||
isolate, types, position,
|
|
||||||
ArrayList::Add(isolate, position_specific_types, type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SetFeedback(*types);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<int> FeedbackNexus::GetSourcePositions() const {
|
|
||||||
DCHECK(IsTypeProfileKind(kind()));
|
|
||||||
std::vector<int> source_positions;
|
|
||||||
Isolate* isolate = GetIsolate();
|
|
||||||
|
|
||||||
MaybeObject const feedback = GetFeedback();
|
|
||||||
|
|
||||||
if (feedback == UninitializedSentinel()) {
|
|
||||||
return source_positions;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<SimpleNumberDictionary> types(
|
|
||||||
SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
|
|
||||||
isolate);
|
|
||||||
|
|
||||||
for (int index = SimpleNumberDictionary::kElementsStartIndex;
|
|
||||||
index < types->length(); index += SimpleNumberDictionary::kEntrySize) {
|
|
||||||
int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
|
|
||||||
Object key = types->get(key_index);
|
|
||||||
if (key.IsSmi()) {
|
|
||||||
int position = Smi::cast(key).value();
|
|
||||||
source_positions.push_back(position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return source_positions;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Handle<String>> FeedbackNexus::GetTypesForSourcePositions(
|
|
||||||
uint32_t position) const {
|
|
||||||
DCHECK(IsTypeProfileKind(kind()));
|
|
||||||
Isolate* isolate = GetIsolate();
|
|
||||||
|
|
||||||
MaybeObject const feedback = GetFeedback();
|
|
||||||
std::vector<Handle<String>> types_for_position;
|
|
||||||
if (feedback == UninitializedSentinel()) {
|
|
||||||
return types_for_position;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<SimpleNumberDictionary> types(
|
|
||||||
SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
|
|
||||||
isolate);
|
|
||||||
|
|
||||||
InternalIndex entry = types->FindEntry(isolate, position);
|
|
||||||
if (entry.is_not_found()) return types_for_position;
|
|
||||||
|
|
||||||
DCHECK(types->ValueAt(entry).IsArrayList());
|
|
||||||
Handle<ArrayList> position_specific_types =
|
|
||||||
Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)), isolate);
|
|
||||||
for (int i = 0; i < position_specific_types->Length(); i++) {
|
|
||||||
Object t = position_specific_types->Get(i);
|
|
||||||
types_for_position.push_back(Handle<String>(String::cast(t), isolate));
|
|
||||||
}
|
|
||||||
|
|
||||||
return types_for_position;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FeedbackNexus::ResetTypeProfile() {
|
|
||||||
DCHECK(IsTypeProfileKind(kind()));
|
|
||||||
SetFeedback(UninitializedSentinel());
|
|
||||||
}
|
|
||||||
|
|
||||||
FeedbackIterator::FeedbackIterator(const FeedbackNexus* nexus)
|
FeedbackIterator::FeedbackIterator(const FeedbackNexus* nexus)
|
||||||
: done_(false), index_(-1), state_(kOther) {
|
: done_(false), index_(-1), state_(kOther) {
|
||||||
DCHECK(
|
DCHECK(
|
||||||
|
@ -62,7 +62,6 @@ enum class FeedbackSlotKind : uint8_t {
|
|||||||
kBinaryOp,
|
kBinaryOp,
|
||||||
kCompareOp,
|
kCompareOp,
|
||||||
kDefineKeyedOwnPropertyInLiteral,
|
kDefineKeyedOwnPropertyInLiteral,
|
||||||
kTypeProfile,
|
|
||||||
kLiteral,
|
kLiteral,
|
||||||
kForIn,
|
kForIn,
|
||||||
kInstanceOf,
|
kInstanceOf,
|
||||||
@ -134,10 +133,6 @@ inline bool IsGlobalICKind(FeedbackSlotKind kind) {
|
|||||||
return IsLoadGlobalICKind(kind) || IsStoreGlobalICKind(kind);
|
return IsLoadGlobalICKind(kind) || IsStoreGlobalICKind(kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool IsTypeProfileKind(FeedbackSlotKind kind) {
|
|
||||||
return kind == FeedbackSlotKind::kTypeProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool IsCloneObjectKind(FeedbackSlotKind kind) {
|
inline bool IsCloneObjectKind(FeedbackSlotKind kind) {
|
||||||
return kind == FeedbackSlotKind::kCloneObject;
|
return kind == FeedbackSlotKind::kCloneObject;
|
||||||
}
|
}
|
||||||
@ -321,8 +316,6 @@ class FeedbackVector
|
|||||||
V8_EXPORT_PRIVATE FeedbackSlotKind GetKind(FeedbackSlot slot,
|
V8_EXPORT_PRIVATE FeedbackSlotKind GetKind(FeedbackSlot slot,
|
||||||
AcquireLoadTag tag) const;
|
AcquireLoadTag tag) const;
|
||||||
|
|
||||||
FeedbackSlot GetTypeProfileSlot() const;
|
|
||||||
|
|
||||||
V8_EXPORT_PRIVATE static Handle<FeedbackVector> New(
|
V8_EXPORT_PRIVATE static Handle<FeedbackVector> New(
|
||||||
Isolate* isolate, Handle<SharedFunctionInfo> shared,
|
Isolate* isolate, Handle<SharedFunctionInfo> shared,
|
||||||
Handle<ClosureFeedbackCellArray> closure_feedback_cell_array,
|
Handle<ClosureFeedbackCellArray> closure_feedback_cell_array,
|
||||||
@ -345,7 +338,6 @@ class FeedbackVector
|
|||||||
DEFINE_SLOT_KIND_PREDICATE(IsDefineNamedOwnIC)
|
DEFINE_SLOT_KIND_PREDICATE(IsDefineNamedOwnIC)
|
||||||
DEFINE_SLOT_KIND_PREDICATE(IsStoreGlobalIC)
|
DEFINE_SLOT_KIND_PREDICATE(IsStoreGlobalIC)
|
||||||
DEFINE_SLOT_KIND_PREDICATE(IsKeyedStoreIC)
|
DEFINE_SLOT_KIND_PREDICATE(IsKeyedStoreIC)
|
||||||
DEFINE_SLOT_KIND_PREDICATE(IsTypeProfile)
|
|
||||||
#undef DEFINE_SLOT_KIND_PREDICATE
|
#undef DEFINE_SLOT_KIND_PREDICATE
|
||||||
|
|
||||||
// Returns typeof mode encoded into kind of given slot.
|
// Returns typeof mode encoded into kind of given slot.
|
||||||
@ -436,13 +428,6 @@ class V8_EXPORT_PRIVATE FeedbackVectorSpec {
|
|||||||
return slot_kinds_.at(slot.ToInt());
|
return slot_kinds_.at(slot.ToInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasTypeProfileSlot() const;
|
|
||||||
|
|
||||||
// If used, the TypeProfileSlot is always added as the first slot and its
|
|
||||||
// index is constant. If other slots are added before the TypeProfileSlot,
|
|
||||||
// this number changes.
|
|
||||||
static const int kTypeProfileSlotIndex = 0;
|
|
||||||
|
|
||||||
FeedbackSlot AddCallICSlot() { return AddSlot(FeedbackSlotKind::kCall); }
|
FeedbackSlot AddCallICSlot() { return AddSlot(FeedbackSlotKind::kCall); }
|
||||||
|
|
||||||
FeedbackSlot AddLoadICSlot() {
|
FeedbackSlot AddLoadICSlot() {
|
||||||
@ -524,8 +509,6 @@ class V8_EXPORT_PRIVATE FeedbackVectorSpec {
|
|||||||
return AddSlot(FeedbackSlotKind::kDefineKeyedOwnPropertyInLiteral);
|
return AddSlot(FeedbackSlotKind::kDefineKeyedOwnPropertyInLiteral);
|
||||||
}
|
}
|
||||||
|
|
||||||
FeedbackSlot AddTypeProfileSlot();
|
|
||||||
|
|
||||||
FeedbackSlot AddCloneObjectSlot() {
|
FeedbackSlot AddCloneObjectSlot() {
|
||||||
return AddSlot(FeedbackSlotKind::kCloneObject);
|
return AddSlot(FeedbackSlotKind::kCloneObject);
|
||||||
}
|
}
|
||||||
@ -611,7 +594,6 @@ class FeedbackMetadata : public HeapObject {
|
|||||||
DECL_VERIFIER(FeedbackMetadata)
|
DECL_VERIFIER(FeedbackMetadata)
|
||||||
|
|
||||||
static const char* Kind2String(FeedbackSlotKind kind);
|
static const char* Kind2String(FeedbackSlotKind kind);
|
||||||
bool HasTypeProfileSlot() const;
|
|
||||||
|
|
||||||
// Garbage collection support.
|
// Garbage collection support.
|
||||||
// This includes any necessary padding at the end of the object for pointer
|
// This includes any necessary padding at the end of the object for pointer
|
||||||
@ -902,16 +884,6 @@ class V8_EXPORT_PRIVATE FeedbackNexus final {
|
|||||||
// Make sure we don't overflow the smi.
|
// Make sure we don't overflow the smi.
|
||||||
static_assert(LEXICAL_MODE_BIT_FIELDS_Ranges::kBitsCount <= kSmiValueSize);
|
static_assert(LEXICAL_MODE_BIT_FIELDS_Ranges::kBitsCount <= kSmiValueSize);
|
||||||
|
|
||||||
// For TypeProfile feedback vector slots.
|
|
||||||
// ResetTypeProfile will always reset type profile information.
|
|
||||||
void ResetTypeProfile();
|
|
||||||
|
|
||||||
// Add a type to the list of types for source position <position>.
|
|
||||||
void Collect(Handle<String> type, int position);
|
|
||||||
|
|
||||||
std::vector<int> GetSourcePositions() const;
|
|
||||||
std::vector<Handle<String>> GetTypesForSourcePositions(uint32_t pos) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename FeedbackType>
|
template <typename FeedbackType>
|
||||||
inline void SetFeedback(FeedbackType feedback,
|
inline void SetFeedback(FeedbackType feedback,
|
||||||
|
@ -628,7 +628,6 @@ void JSFunction::InitializeFeedbackCell(
|
|||||||
// profile and more precise code coverage.
|
// profile and more precise code coverage.
|
||||||
v8_flags.log_function_events ||
|
v8_flags.log_function_events ||
|
||||||
!isolate->is_best_effort_code_coverage() ||
|
!isolate->is_best_effort_code_coverage() ||
|
||||||
isolate->is_collecting_type_profile() ||
|
|
||||||
function->shared().sparkplug_compiled();
|
function->shared().sparkplug_compiled();
|
||||||
|
|
||||||
if (needs_feedback_vector) {
|
if (needs_feedback_vector) {
|
||||||
|
@ -28,7 +28,6 @@ UnoptimizedCompileFlags::UnoptimizedCompileFlags(Isolate* isolate,
|
|||||||
function_kind_(FunctionKind::kNormalFunction),
|
function_kind_(FunctionKind::kNormalFunction),
|
||||||
function_syntax_kind_(FunctionSyntaxKind::kDeclaration),
|
function_syntax_kind_(FunctionSyntaxKind::kDeclaration),
|
||||||
parsing_while_debugging_(ParsingWhileDebugging::kNo) {
|
parsing_while_debugging_(ParsingWhileDebugging::kNo) {
|
||||||
set_collect_type_profile(isolate->is_collecting_type_profile());
|
|
||||||
set_coverage_enabled(!isolate->is_best_effort_code_coverage());
|
set_coverage_enabled(!isolate->is_best_effort_code_coverage());
|
||||||
set_block_coverage_enabled(isolate->is_block_code_coverage());
|
set_block_coverage_enabled(isolate->is_block_code_coverage());
|
||||||
set_might_always_turbofan(v8_flags.always_turbofan ||
|
set_might_always_turbofan(v8_flags.always_turbofan ||
|
||||||
@ -60,15 +59,6 @@ UnoptimizedCompileFlags UnoptimizedCompileFlags::ForFunctionCompile(
|
|||||||
#endif // V8_ENABLE_WEBASSEMBLY
|
#endif // V8_ENABLE_WEBASSEMBLY
|
||||||
flags.set_is_repl_mode(shared.is_repl_mode());
|
flags.set_is_repl_mode(shared.is_repl_mode());
|
||||||
|
|
||||||
// CollectTypeProfile uses its own feedback slots. If we have existing
|
|
||||||
// FeedbackMetadata, we can only collect type profile if the feedback vector
|
|
||||||
// has the appropriate slots.
|
|
||||||
flags.set_collect_type_profile(
|
|
||||||
isolate->is_collecting_type_profile() &&
|
|
||||||
(shared.HasFeedbackMetadata()
|
|
||||||
? shared.feedback_metadata().HasTypeProfileSlot()
|
|
||||||
: script.IsUserJavaScript()));
|
|
||||||
|
|
||||||
// Do not support re-parsing top-level function of a wrapped script.
|
// Do not support re-parsing top-level function of a wrapped script.
|
||||||
DCHECK_IMPLIES(flags.is_toplevel(), !script.is_wrapped());
|
DCHECK_IMPLIES(flags.is_toplevel(), !script.is_wrapped());
|
||||||
|
|
||||||
@ -82,8 +72,8 @@ UnoptimizedCompileFlags UnoptimizedCompileFlags::ForScriptCompile(
|
|||||||
|
|
||||||
flags.SetFlagsForFunctionFromScript(script);
|
flags.SetFlagsForFunctionFromScript(script);
|
||||||
flags.SetFlagsForToplevelCompile(
|
flags.SetFlagsForToplevelCompile(
|
||||||
isolate->is_collecting_type_profile(), script.IsUserJavaScript(),
|
script.IsUserJavaScript(), flags.outer_language_mode(),
|
||||||
flags.outer_language_mode(), construct_repl_mode(script.is_repl_mode()),
|
construct_repl_mode(script.is_repl_mode()),
|
||||||
script.origin_options().IsModule() ? ScriptType::kModule
|
script.origin_options().IsModule() ? ScriptType::kModule
|
||||||
: ScriptType::kClassic,
|
: ScriptType::kClassic,
|
||||||
v8_flags.lazy);
|
v8_flags.lazy);
|
||||||
@ -99,8 +89,7 @@ UnoptimizedCompileFlags UnoptimizedCompileFlags::ForToplevelCompile(
|
|||||||
Isolate* isolate, bool is_user_javascript, LanguageMode language_mode,
|
Isolate* isolate, bool is_user_javascript, LanguageMode language_mode,
|
||||||
REPLMode repl_mode, ScriptType type, bool lazy) {
|
REPLMode repl_mode, ScriptType type, bool lazy) {
|
||||||
UnoptimizedCompileFlags flags(isolate, isolate->GetNextScriptId());
|
UnoptimizedCompileFlags flags(isolate, isolate->GetNextScriptId());
|
||||||
flags.SetFlagsForToplevelCompile(isolate->is_collecting_type_profile(),
|
flags.SetFlagsForToplevelCompile(is_user_javascript, language_mode, repl_mode,
|
||||||
is_user_javascript, language_mode, repl_mode,
|
|
||||||
type, lazy);
|
type, lazy);
|
||||||
|
|
||||||
LOG(isolate, ScriptEvent(V8FileLogger::ScriptEventType::kReserveId,
|
LOG(isolate, ScriptEvent(V8FileLogger::ScriptEventType::kReserveId,
|
||||||
@ -143,13 +132,11 @@ void UnoptimizedCompileFlags::SetFlagsFromFunction(T function) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UnoptimizedCompileFlags::SetFlagsForToplevelCompile(
|
void UnoptimizedCompileFlags::SetFlagsForToplevelCompile(
|
||||||
bool is_collecting_type_profile, bool is_user_javascript,
|
bool is_user_javascript, LanguageMode language_mode, REPLMode repl_mode,
|
||||||
LanguageMode language_mode, REPLMode repl_mode, ScriptType type,
|
ScriptType type, bool lazy) {
|
||||||
bool lazy) {
|
|
||||||
set_is_toplevel(true);
|
set_is_toplevel(true);
|
||||||
set_allow_lazy_parsing(lazy);
|
set_allow_lazy_parsing(lazy);
|
||||||
set_allow_lazy_compile(lazy);
|
set_allow_lazy_compile(lazy);
|
||||||
set_collect_type_profile(is_user_javascript && is_collecting_type_profile);
|
|
||||||
set_outer_language_mode(
|
set_outer_language_mode(
|
||||||
stricter_language_mode(outer_language_mode(), language_mode));
|
stricter_language_mode(outer_language_mode(), language_mode));
|
||||||
set_is_repl_mode((repl_mode == REPLMode::kYes));
|
set_is_repl_mode((repl_mode == REPLMode::kYes));
|
||||||
@ -278,8 +265,7 @@ Handle<Script> ParseInfo::CreateScript(
|
|||||||
} else if (flags().is_eval()) {
|
} else if (flags().is_eval()) {
|
||||||
raw_script.set_compilation_type(Script::COMPILATION_TYPE_EVAL);
|
raw_script.set_compilation_type(Script::COMPILATION_TYPE_EVAL);
|
||||||
}
|
}
|
||||||
CheckFlagsForToplevelCompileFromScript(raw_script,
|
CheckFlagsForToplevelCompileFromScript(raw_script);
|
||||||
isolate->is_collecting_type_profile());
|
|
||||||
|
|
||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
@ -309,12 +295,9 @@ void ParseInfo::set_character_stream(
|
|||||||
character_stream_.swap(character_stream);
|
character_stream_.swap(character_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParseInfo::CheckFlagsForToplevelCompileFromScript(
|
void ParseInfo::CheckFlagsForToplevelCompileFromScript(Script script) {
|
||||||
Script script, bool is_collecting_type_profile) {
|
|
||||||
CheckFlagsForFunctionFromScript(script);
|
CheckFlagsForFunctionFromScript(script);
|
||||||
DCHECK(flags().is_toplevel());
|
DCHECK(flags().is_toplevel());
|
||||||
DCHECK_EQ(flags().collect_type_profile(),
|
|
||||||
is_collecting_type_profile && script.IsUserJavaScript());
|
|
||||||
DCHECK_EQ(flags().is_repl_mode(), script.is_repl_mode());
|
DCHECK_EQ(flags().is_repl_mode(), script.is_repl_mode());
|
||||||
|
|
||||||
if (script.is_wrapped()) {
|
if (script.is_wrapped()) {
|
||||||
|
@ -48,7 +48,6 @@ class Zone;
|
|||||||
V(is_module, bool, 1, _) \
|
V(is_module, bool, 1, _) \
|
||||||
V(allow_lazy_parsing, bool, 1, _) \
|
V(allow_lazy_parsing, bool, 1, _) \
|
||||||
V(is_lazy_compile, bool, 1, _) \
|
V(is_lazy_compile, bool, 1, _) \
|
||||||
V(collect_type_profile, bool, 1, _) \
|
|
||||||
V(coverage_enabled, bool, 1, _) \
|
V(coverage_enabled, bool, 1, _) \
|
||||||
V(block_coverage_enabled, bool, 1, _) \
|
V(block_coverage_enabled, bool, 1, _) \
|
||||||
V(is_asm_wasm_broken, bool, 1, _) \
|
V(is_asm_wasm_broken, bool, 1, _) \
|
||||||
@ -140,8 +139,7 @@ class V8_EXPORT_PRIVATE UnoptimizedCompileFlags {
|
|||||||
// SharedFunctionInfo |function|
|
// SharedFunctionInfo |function|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void SetFlagsFromFunction(T function);
|
void SetFlagsFromFunction(T function);
|
||||||
void SetFlagsForToplevelCompile(bool is_collecting_type_profile,
|
void SetFlagsForToplevelCompile(bool is_user_javascript,
|
||||||
bool is_user_javascript,
|
|
||||||
LanguageMode language_mode,
|
LanguageMode language_mode,
|
||||||
REPLMode repl_mode, ScriptType type,
|
REPLMode repl_mode, ScriptType type,
|
||||||
bool lazy);
|
bool lazy);
|
||||||
@ -345,8 +343,7 @@ class V8_EXPORT_PRIVATE ParseInfo {
|
|||||||
ReusableUnoptimizedCompileState* reusable_state,
|
ReusableUnoptimizedCompileState* reusable_state,
|
||||||
uintptr_t stack_limit, RuntimeCallStats* runtime_call_stats);
|
uintptr_t stack_limit, RuntimeCallStats* runtime_call_stats);
|
||||||
|
|
||||||
void CheckFlagsForToplevelCompileFromScript(Script script,
|
void CheckFlagsForToplevelCompileFromScript(Script script);
|
||||||
bool is_collecting_type_profile);
|
|
||||||
|
|
||||||
//------------- Inputs to parsing and scope analysis -----------------------
|
//------------- Inputs to parsing and scope analysis -----------------------
|
||||||
const UnoptimizedCompileFlags flags_;
|
const UnoptimizedCompileFlags flags_;
|
||||||
|
@ -1175,35 +1175,6 @@ RUNTIME_FUNCTION(Runtime_DefineKeyedOwnPropertyInLiteral) {
|
|||||||
return *value;
|
return *value;
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_CollectTypeProfile) {
|
|
||||||
HandleScope scope(isolate);
|
|
||||||
DCHECK_EQ(3, args.length());
|
|
||||||
int position = args.smi_value_at(0);
|
|
||||||
Handle<Object> value = args.at(1);
|
|
||||||
Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
|
|
||||||
|
|
||||||
if (maybe_vector->IsUndefined()) {
|
|
||||||
return ReadOnlyRoots(isolate).undefined_value();
|
|
||||||
}
|
|
||||||
Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
|
|
||||||
|
|
||||||
Handle<String> type = Object::TypeOf(isolate, value);
|
|
||||||
if (value->IsJSReceiver()) {
|
|
||||||
Handle<JSReceiver> object = Handle<JSReceiver>::cast(value);
|
|
||||||
type = JSReceiver::GetConstructorName(isolate, object);
|
|
||||||
} else if (value->IsNull(isolate)) {
|
|
||||||
// typeof(null) is object. But it's more user-friendly to annotate
|
|
||||||
// null as type "null".
|
|
||||||
type = Handle<String>(ReadOnlyRoots(isolate).null_string(), isolate);
|
|
||||||
}
|
|
||||||
|
|
||||||
DCHECK(vector->metadata().HasTypeProfileSlot());
|
|
||||||
FeedbackNexus nexus(vector, vector->GetTypeProfileSlot());
|
|
||||||
nexus.Collect(type, position);
|
|
||||||
|
|
||||||
return ReadOnlyRoots(isolate).undefined_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_HasFastPackedElements) {
|
RUNTIME_FUNCTION(Runtime_HasFastPackedElements) {
|
||||||
SealHandleScope shs(isolate);
|
SealHandleScope shs(isolate);
|
||||||
DCHECK_EQ(1, args.length());
|
DCHECK_EQ(1, args.length());
|
||||||
|
@ -300,7 +300,6 @@ namespace internal {
|
|||||||
F(AddDictionaryProperty, 3, 1) \
|
F(AddDictionaryProperty, 3, 1) \
|
||||||
F(AddPrivateBrand, 4, 1) \
|
F(AddPrivateBrand, 4, 1) \
|
||||||
F(AllocateHeapNumber, 0, 1) \
|
F(AllocateHeapNumber, 0, 1) \
|
||||||
F(CollectTypeProfile, 3, 1) \
|
|
||||||
F(CompleteInobjectSlackTrackingForMap, 1, 1) \
|
F(CompleteInobjectSlackTrackingForMap, 1, 1) \
|
||||||
I(CopyDataProperties, 2, 1) \
|
I(CopyDataProperties, 2, 1) \
|
||||||
I(CopyDataPropertiesWithExcludedPropertiesOnStack, -1 /* >= 1 */, 1) \
|
I(CopyDataPropertiesWithExcludedPropertiesOnStack, -1 /* >= 1 */, 1) \
|
||||||
|
@ -60,16 +60,6 @@
|
|||||||
'runtime/get-properties': [SKIP],
|
'runtime/get-properties': [SKIP],
|
||||||
}], # not has_webassembly or variant == jitless
|
}], # not has_webassembly or variant == jitless
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
['lite_mode or variant == jitless', {
|
|
||||||
# Lite mode does not allocate feedback vector.
|
|
||||||
'type-profiler/type-profile-start-stop': [SKIP],
|
|
||||||
'type-profiler/type-profile': [SKIP],
|
|
||||||
'type-profiler/type-profile-with-to-string-tag': [SKIP],
|
|
||||||
'type-profiler/type-profile-with-classes': [SKIP],
|
|
||||||
'type-profiler/type-profile-disable': [SKIP],
|
|
||||||
}], # 'lite_mode or variant == jitless'
|
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
['variant == jitless', {
|
['variant == jitless', {
|
||||||
# https://crbug.com/v8/7777
|
# https://crbug.com/v8/7777
|
||||||
@ -176,7 +166,6 @@
|
|||||||
'runtime/context-destroyed-on-context-collected': [SKIP],
|
'runtime/context-destroyed-on-context-collected': [SKIP],
|
||||||
'runtime/evaluate-async': [SKIP],
|
'runtime/evaluate-async': [SKIP],
|
||||||
'runtime/internal-properties-entries': [SKIP],
|
'runtime/internal-properties-entries': [SKIP],
|
||||||
'type-profiler/type-profile-start-stop': [SKIP],
|
|
||||||
}], # gc_stress
|
}], # gc_stress
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
@ -529,11 +518,6 @@
|
|||||||
'sessions/runtime-evaluate': [SKIP],
|
'sessions/runtime-evaluate': [SKIP],
|
||||||
'sessions/runtime-evaluate-exception': [SKIP],
|
'sessions/runtime-evaluate-exception': [SKIP],
|
||||||
'sessions/runtime-remote-object': [SKIP],
|
'sessions/runtime-remote-object': [SKIP],
|
||||||
'type-profiler/type-profile': [SKIP],
|
|
||||||
'type-profiler/type-profile-disable': [SKIP],
|
|
||||||
'type-profiler/type-profile-start-stop': [SKIP],
|
|
||||||
'type-profiler/type-profile-with-classes': [SKIP],
|
|
||||||
'type-profiler/type-profile-with-to-string-tag': [SKIP],
|
|
||||||
'regress/regress-crbug-1195927': [SKIP],
|
'regress/regress-crbug-1195927': [SKIP],
|
||||||
}], # third_party_heap
|
}], # third_party_heap
|
||||||
|
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
Turn Profiler.startTypeProfile on and off.
|
|
||||||
|
|
||||||
function g(/*Object*/a, /*Array*/b, /*null*/c) {
|
|
||||||
return 'bye';
|
|
||||||
/*string*/};
|
|
||||||
g({}, [], null);
|
|
||||||
|
|
||||||
[
|
|
||||||
]
|
|
@ -1,45 +0,0 @@
|
|||||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
const source =
|
|
||||||
`
|
|
||||||
function g(a, b, c) {
|
|
||||||
return 'bye';
|
|
||||||
};
|
|
||||||
g({}, [], null);
|
|
||||||
`;
|
|
||||||
|
|
||||||
let {session, contextGroup, Protocol} = InspectorTest.start("Turn " +
|
|
||||||
"Profiler.startTypeProfile on and off.");
|
|
||||||
|
|
||||||
(async function testTypeProfile() {
|
|
||||||
Protocol.Runtime.enable();
|
|
||||||
let {result: {scriptId}} = await Protocol.Runtime.compileScript({
|
|
||||||
expression: source,
|
|
||||||
sourceURL: arguments.callee.name, persistScript: true
|
|
||||||
});
|
|
||||||
await Protocol.Profiler.enable();
|
|
||||||
// Start, run, take.
|
|
||||||
await Protocol.Profiler.startTypeProfile();
|
|
||||||
Protocol.Runtime.runScript({scriptId});
|
|
||||||
|
|
||||||
let typeProfiles = await Protocol.Profiler.takeTypeProfile();
|
|
||||||
session.logTypeProfile(typeProfiles.result.result[0],
|
|
||||||
source);
|
|
||||||
|
|
||||||
// This should delete all data.
|
|
||||||
Protocol.Profiler.stopTypeProfile();
|
|
||||||
|
|
||||||
await Protocol.Profiler.startTypeProfile();
|
|
||||||
typeProfiles = await Protocol.Profiler.takeTypeProfile();
|
|
||||||
|
|
||||||
// Should be empty because no code was run since start.
|
|
||||||
InspectorTest.logMessage(typeProfiles.result.result);
|
|
||||||
|
|
||||||
Protocol.Profiler.stopTypeProfile();
|
|
||||||
|
|
||||||
Protocol.Profiler.disable();
|
|
||||||
await Protocol.Runtime.disable();
|
|
||||||
InspectorTest.completeTest();
|
|
||||||
})();
|
|
@ -1,9 +0,0 @@
|
|||||||
Test collecting type profile data with Profiler.takeTypeProfile.
|
|
||||||
|
|
||||||
function f(/*Object, number, undefined*/a, /*Array, number, null*/b, /*boolean, Object, symbol*/c) {
|
|
||||||
return 'bye';
|
|
||||||
/*string*/};
|
|
||||||
f({}, [], true);
|
|
||||||
f(3, 2.3, {a: 42});
|
|
||||||
f(undefined, null, Symbol('hello'));
|
|
||||||
/*string*/
|
|
@ -1,51 +0,0 @@
|
|||||||
Turn Profiler.startTypeProfile on and off.
|
|
||||||
|
|
||||||
Running test: testTypeProfile
|
|
||||||
|
|
||||||
function g(/*Object*/a, /*Array*/b, /*null*/c) {
|
|
||||||
return 'first';
|
|
||||||
/*string*/};
|
|
||||||
g({}, [], null);
|
|
||||||
|
|
||||||
|
|
||||||
Running test: testTypeProfileFromDifferentSource
|
|
||||||
|
|
||||||
function f(/*null*/a) {
|
|
||||||
return 'second';
|
|
||||||
/*string*/};
|
|
||||||
f(null);
|
|
||||||
|
|
||||||
|
|
||||||
Running test: testStopTypeProfileDeletesFeedback
|
|
||||||
[
|
|
||||||
]
|
|
||||||
|
|
||||||
Running test: testTypeProfileWithoutStartingItFirst
|
|
||||||
Type profile has not been started.
|
|
||||||
|
|
||||||
Running test: testTypeProfileAfterStoppingIt
|
|
||||||
Type profile has not been started.
|
|
||||||
|
|
||||||
Running test: testStartTypeProfileAfterRunning
|
|
||||||
{
|
|
||||||
id : <messageId>
|
|
||||||
result : {
|
|
||||||
result : [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Running test: testTypeProfileForTwoSources
|
|
||||||
|
|
||||||
function g(/*Object*/a, /*Array*/b, /*null*/c) {
|
|
||||||
return 'first';
|
|
||||||
/*string*/};
|
|
||||||
g({}, [], null);
|
|
||||||
|
|
||||||
|
|
||||||
function f(/*null*/a) {
|
|
||||||
return 'second';
|
|
||||||
/*string*/};
|
|
||||||
f(null);
|
|
||||||
|
|
||||||
Running test: testStopTwice
|
|
@ -1,176 +0,0 @@
|
|||||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
const source1 =
|
|
||||||
`
|
|
||||||
function g(a, b, c) {
|
|
||||||
return 'first';
|
|
||||||
};
|
|
||||||
g({}, [], null);
|
|
||||||
`;
|
|
||||||
|
|
||||||
const source2 =
|
|
||||||
`
|
|
||||||
function f(a) {
|
|
||||||
return 'second';
|
|
||||||
};
|
|
||||||
f(null);
|
|
||||||
`;
|
|
||||||
|
|
||||||
let {session, contextGroup, Protocol} = InspectorTest.start("Turn " +
|
|
||||||
"Profiler.startTypeProfile on and off.");
|
|
||||||
|
|
||||||
InspectorTest.runAsyncTestSuite([
|
|
||||||
async function testTypeProfile() {
|
|
||||||
Protocol.Runtime.enable();
|
|
||||||
let {result: {scriptId}} = await Protocol.Runtime.compileScript({
|
|
||||||
expression: source1,
|
|
||||||
sourceURL: arguments.callee.name, persistScript: true
|
|
||||||
});
|
|
||||||
await Protocol.Profiler.enable();
|
|
||||||
|
|
||||||
// Start, run, take.
|
|
||||||
await Protocol.Profiler.startTypeProfile();
|
|
||||||
Protocol.Runtime.runScript({scriptId});
|
|
||||||
|
|
||||||
let typeProfiles = await Protocol.Profiler.takeTypeProfile();
|
|
||||||
await session.logTypeProfile(typeProfiles.result.result[0],
|
|
||||||
source1);
|
|
||||||
|
|
||||||
Protocol.Profiler.stopTypeProfile();
|
|
||||||
Protocol.Profiler.disable();
|
|
||||||
await Protocol.Runtime.disable();
|
|
||||||
},
|
|
||||||
async function testTypeProfileFromDifferentSource() {
|
|
||||||
Protocol.Runtime.enable();
|
|
||||||
let {result: {scriptId}} = await Protocol.Runtime.compileScript({
|
|
||||||
expression: source2,
|
|
||||||
sourceURL: arguments.callee.name, persistScript: true
|
|
||||||
});
|
|
||||||
await Protocol.Profiler.enable();
|
|
||||||
|
|
||||||
// Start, run different script, take.
|
|
||||||
await Protocol.Profiler.startTypeProfile();
|
|
||||||
Protocol.Runtime.runScript({scriptId});
|
|
||||||
|
|
||||||
let typeProfiles = await Protocol.Profiler.takeTypeProfile();
|
|
||||||
await session.logTypeProfile(typeProfiles.result.result[0],
|
|
||||||
source2);
|
|
||||||
|
|
||||||
Protocol.Profiler.stopTypeProfile();
|
|
||||||
Protocol.Profiler.disable();
|
|
||||||
await Protocol.Runtime.disable();
|
|
||||||
},
|
|
||||||
async function testStopTypeProfileDeletesFeedback() {
|
|
||||||
Protocol.Runtime.enable();
|
|
||||||
let {result: {scriptId}} = await Protocol.Runtime.compileScript({
|
|
||||||
expression: source1,
|
|
||||||
sourceURL: arguments.callee.name, persistScript: true
|
|
||||||
});
|
|
||||||
await Protocol.Profiler.enable();
|
|
||||||
|
|
||||||
// Start, run, stop.
|
|
||||||
await Protocol.Profiler.startTypeProfile();
|
|
||||||
Protocol.Runtime.runScript({scriptId});
|
|
||||||
await Protocol.Profiler.stopTypeProfile();
|
|
||||||
|
|
||||||
// Start, take. Should be empty, because no code was run.
|
|
||||||
await Protocol.Profiler.startTypeProfile();
|
|
||||||
let typeProfiles = await Protocol.Profiler.takeTypeProfile();
|
|
||||||
InspectorTest.logMessage(typeProfiles.result.result);
|
|
||||||
await Protocol.Profiler.stopTypeProfile();
|
|
||||||
|
|
||||||
Protocol.Profiler.disable();
|
|
||||||
await Protocol.Runtime.disable();
|
|
||||||
},
|
|
||||||
async function testTypeProfileWithoutStartingItFirst() {
|
|
||||||
Protocol.Runtime.enable();
|
|
||||||
let {result: {scriptId}} = await Protocol.Runtime.compileScript({ expression: source1,
|
|
||||||
sourceURL: arguments.callee.name, persistScript: true });
|
|
||||||
Protocol.Runtime.runScript({ scriptId });
|
|
||||||
await Protocol.Profiler.enable();
|
|
||||||
|
|
||||||
// This should return an error because type profile was never started.
|
|
||||||
let typeProfiles = await Protocol.Profiler.takeTypeProfile();
|
|
||||||
InspectorTest.logObject(typeProfiles.error.message);
|
|
||||||
|
|
||||||
Protocol.Profiler.disable();
|
|
||||||
await Protocol.Runtime.disable();
|
|
||||||
},
|
|
||||||
async function testTypeProfileAfterStoppingIt() {
|
|
||||||
Protocol.Runtime.enable();
|
|
||||||
let {result: {scriptId}} = await Protocol.Runtime.compileScript({ expression: source1,
|
|
||||||
sourceURL: arguments.callee.name, persistScript: true });
|
|
||||||
Protocol.Runtime.runScript({ scriptId });
|
|
||||||
await Protocol.Profiler.enable();
|
|
||||||
await Protocol.Profiler.startTypeProfile();
|
|
||||||
|
|
||||||
// Make sure that this turns off type profile.
|
|
||||||
await Protocol.Profiler.stopTypeProfile();
|
|
||||||
|
|
||||||
// This should return an error because type profile was stopped.
|
|
||||||
let typeProfiles = await Protocol.Profiler.takeTypeProfile();
|
|
||||||
InspectorTest.logObject(typeProfiles.error.message);
|
|
||||||
|
|
||||||
Protocol.Profiler.disable();
|
|
||||||
await Protocol.Runtime.disable();
|
|
||||||
},
|
|
||||||
async function testStartTypeProfileAfterRunning() {
|
|
||||||
Protocol.Runtime.enable();
|
|
||||||
let {result: {scriptId}} = await Protocol.Runtime.compileScript({
|
|
||||||
expression: source1,
|
|
||||||
sourceURL: arguments.callee.name, persistScript: true
|
|
||||||
});
|
|
||||||
Protocol.Runtime.runScript({scriptId});
|
|
||||||
|
|
||||||
await Protocol.Profiler.enable();
|
|
||||||
await Protocol.Profiler.startTypeProfile();
|
|
||||||
|
|
||||||
let typeProfiles = await Protocol.Profiler.takeTypeProfile();
|
|
||||||
|
|
||||||
// This should be empty because type profile was started after compilation.
|
|
||||||
// Only the outer script is annotated with return value "string" because
|
|
||||||
// that does not depend on runScript().
|
|
||||||
InspectorTest.logMessage(typeProfiles);
|
|
||||||
|
|
||||||
Protocol.Profiler.stopTypeProfile();
|
|
||||||
Protocol.Profiler.disable();
|
|
||||||
await Protocol.Runtime.disable();
|
|
||||||
},
|
|
||||||
async function testTypeProfileForTwoSources() {
|
|
||||||
Protocol.Runtime.enable();
|
|
||||||
let {result: {scriptId: scriptId1}} = await Protocol.Runtime.compileScript({
|
|
||||||
expression: source1,
|
|
||||||
sourceURL: arguments.callee.name, persistScript: true
|
|
||||||
});
|
|
||||||
let {result: {scriptId: scriptId2}} = await Protocol.Runtime.compileScript({
|
|
||||||
expression: source2,
|
|
||||||
sourceURL: arguments.callee.name, persistScript: true
|
|
||||||
});
|
|
||||||
await Protocol.Profiler.enable();
|
|
||||||
|
|
||||||
// Start, run different script, take.
|
|
||||||
await Protocol.Profiler.startTypeProfile();
|
|
||||||
Protocol.Runtime.runScript({scriptId: scriptId1});
|
|
||||||
Protocol.Runtime.runScript({scriptId: scriptId2});
|
|
||||||
|
|
||||||
let typeProfiles = await Protocol.Profiler.takeTypeProfile();
|
|
||||||
await session.logTypeProfile(typeProfiles.result.result[0],
|
|
||||||
source1);
|
|
||||||
await session.logTypeProfile(typeProfiles.result.result[1],
|
|
||||||
source2);
|
|
||||||
|
|
||||||
Protocol.Profiler.stopTypeProfile();
|
|
||||||
Protocol.Profiler.disable();
|
|
||||||
await Protocol.Runtime.disable();
|
|
||||||
},
|
|
||||||
async function testStopTwice() {
|
|
||||||
Protocol.Runtime.enable();
|
|
||||||
await Protocol.Profiler.enable();
|
|
||||||
await Protocol.Profiler.stopTypeProfile();
|
|
||||||
await Protocol.Profiler.stopTypeProfile();
|
|
||||||
Protocol.Profiler.disable();
|
|
||||||
await Protocol.Runtime.disable();
|
|
||||||
},
|
|
||||||
]);
|
|
@ -1,16 +0,0 @@
|
|||||||
Test collecting type profile data with Profiler.takeTypeProfile.
|
|
||||||
|
|
||||||
function f(/*number*/n) {
|
|
||||||
/*undefined*/};
|
|
||||||
f(5);
|
|
||||||
function g(/*Object, number*/a, /*Array, number*/b, /*Flower, Object*/c) {
|
|
||||||
return 'bye';
|
|
||||||
/*string*/};
|
|
||||||
/*undefined*/class Tree {};
|
|
||||||
/*Flower*/class Flower extends Tree{};
|
|
||||||
var f = new Flower();
|
|
||||||
f.constructor = {};
|
|
||||||
f.constructor.name = "Not a flower.";
|
|
||||||
g({}, [], f);
|
|
||||||
g(3, 2.3, {a: 42});
|
|
||||||
/*string*/
|
|
@ -1,41 +0,0 @@
|
|||||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
const source =
|
|
||||||
`
|
|
||||||
function f(n) {
|
|
||||||
};
|
|
||||||
f(5);
|
|
||||||
function g(a, b, c) {
|
|
||||||
return 'bye';
|
|
||||||
};
|
|
||||||
class Tree {};
|
|
||||||
class Flower extends Tree{};
|
|
||||||
var f = new Flower();
|
|
||||||
f.constructor = {};
|
|
||||||
f.constructor.name = "Not a flower.";
|
|
||||||
g({}, [], f);
|
|
||||||
g(3, 2.3, {a: 42});
|
|
||||||
`;
|
|
||||||
|
|
||||||
let {session, contextGroup, Protocol} = InspectorTest.start("Test collecting type profile data with Profiler.takeTypeProfile.");
|
|
||||||
|
|
||||||
(async function testTypeProfile(next) {
|
|
||||||
await Protocol.Profiler.enable();
|
|
||||||
await Protocol.Profiler.startTypeProfile();
|
|
||||||
|
|
||||||
Protocol.Runtime.enable();
|
|
||||||
let {result: {scriptId}} = await Protocol.Runtime.compileScript({ expression: source,
|
|
||||||
sourceURL: arguments.callee.name, persistScript: true });
|
|
||||||
|
|
||||||
Protocol.Runtime.runScript({ scriptId });
|
|
||||||
|
|
||||||
let typeProfiles = await Protocol.Profiler.takeTypeProfile();
|
|
||||||
await session.logTypeProfile(typeProfiles.result.result[0],
|
|
||||||
source);
|
|
||||||
|
|
||||||
Protocol.Profiler.disable();
|
|
||||||
await Protocol.Runtime.disable();
|
|
||||||
InspectorTest.completeTest();
|
|
||||||
})();
|
|
@ -1,17 +0,0 @@
|
|||||||
Test collecting type profile data with Profiler.takeTypeProfile.
|
|
||||||
|
|
||||||
function g(/*Object, number*/a, /*Array, number*/b, /*Dog, Object*/c) {
|
|
||||||
return 'bye';
|
|
||||||
/*string*/};
|
|
||||||
/*undefined*/class Tree {};
|
|
||||||
/*Flower*/class Flower extends Tree{};
|
|
||||||
var f = new Flower();
|
|
||||||
// We store the type when a variable is used. If a toStringTag is
|
|
||||||
// changes the type, we want to collect that changed feedback.
|
|
||||||
// This tests ensures that we collect that information rather than
|
|
||||||
// for example infer the types from the internal map, which wouldn't
|
|
||||||
// know about a toStringTag.
|
|
||||||
f[Symbol.toStringTag] = 'Dog';
|
|
||||||
g({}, [], f);
|
|
||||||
g(3, 2.3, {a: 42});
|
|
||||||
/*string*/
|
|
@ -1,44 +0,0 @@
|
|||||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
const source =
|
|
||||||
`
|
|
||||||
function g(a, b, c) {
|
|
||||||
return 'bye';
|
|
||||||
};
|
|
||||||
class Tree {};
|
|
||||||
class Flower extends Tree{};
|
|
||||||
var f = new Flower();
|
|
||||||
// We store the type when a variable is used. If a toStringTag is
|
|
||||||
// changes the type, we want to collect that changed feedback.
|
|
||||||
// This tests ensures that we collect that information rather than
|
|
||||||
// for example infer the types from the internal map, which wouldn't
|
|
||||||
// know about a toStringTag.
|
|
||||||
f[Symbol.toStringTag] = 'Dog';
|
|
||||||
g({}, [], f);
|
|
||||||
g(3, 2.3, {a: 42});
|
|
||||||
`;
|
|
||||||
|
|
||||||
let {session, contextGroup, Protocol} = InspectorTest.start("Test collecting " +
|
|
||||||
"type profile data with Profiler.takeTypeProfile.");
|
|
||||||
|
|
||||||
(async function testTypeProfile() {
|
|
||||||
await Protocol.Profiler.enable();
|
|
||||||
await Protocol.Profiler.startTypeProfile();
|
|
||||||
|
|
||||||
Protocol.Runtime.enable();
|
|
||||||
let {result: {scriptId}} = await Protocol.Runtime.compileScript({ expression: source,
|
|
||||||
sourceURL: arguments.callee.name, persistScript: true });
|
|
||||||
Protocol.Runtime.runScript({ scriptId });
|
|
||||||
await Protocol.Profiler.startTypeProfile();
|
|
||||||
|
|
||||||
let typeProfiles = await Protocol.Profiler.takeTypeProfile();
|
|
||||||
await session.logTypeProfile(typeProfiles.result.result[0],
|
|
||||||
source);
|
|
||||||
|
|
||||||
Protocol.Profiler.stopTypeProfile();
|
|
||||||
Protocol.Profiler.disable();
|
|
||||||
await Protocol.Runtime.disable();
|
|
||||||
InspectorTest.completeTest();
|
|
||||||
})();
|
|
@ -1,37 +0,0 @@
|
|||||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
const source =
|
|
||||||
`
|
|
||||||
function f(a, b, c) {
|
|
||||||
return 'bye';
|
|
||||||
};
|
|
||||||
f({}, [], true);
|
|
||||||
f(3, 2.3, {a: 42});
|
|
||||||
f(undefined, null, Symbol('hello'));
|
|
||||||
`;
|
|
||||||
|
|
||||||
let {session, contextGroup, Protocol} = InspectorTest.start("Test collecting type profile data with Profiler.takeTypeProfile.");
|
|
||||||
|
|
||||||
(async function testTypeProfile() {
|
|
||||||
await Protocol.Profiler.enable();
|
|
||||||
await Protocol.Profiler.startTypeProfile();
|
|
||||||
|
|
||||||
Protocol.Runtime.enable();
|
|
||||||
let {result: {scriptId}} = await Protocol.Runtime.compileScript({
|
|
||||||
expression: source,
|
|
||||||
sourceURL: arguments.callee.name,
|
|
||||||
persistScript: true
|
|
||||||
});
|
|
||||||
Protocol.Runtime.runScript({ scriptId });
|
|
||||||
|
|
||||||
let typeProfiles = await Protocol.Profiler.takeTypeProfile();
|
|
||||||
await session.logTypeProfile(typeProfiles.result.result[0],
|
|
||||||
source);
|
|
||||||
|
|
||||||
Protocol.Profiler.stopTypeProfile();
|
|
||||||
Protocol.Profiler.disable();
|
|
||||||
await Protocol.Runtime.disable();
|
|
||||||
InspectorTest.completeTest();
|
|
||||||
})();
|
|
@ -1,11 +0,0 @@
|
|||||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
// Flags: --allow-natives-syntax
|
|
||||||
|
|
||||||
function f(a, b, c) {
|
|
||||||
return 'bye';
|
|
||||||
};
|
|
||||||
|
|
||||||
%CollectTypeProfile(0, f, undefined);
|
|
@ -484,10 +484,6 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
|||||||
// Insert entry for illegal bytecode as this is never willingly emitted.
|
// Insert entry for illegal bytecode as this is never willingly emitted.
|
||||||
scorecard[Bytecodes::ToByte(Bytecode::kIllegal)] = 1;
|
scorecard[Bytecodes::ToByte(Bytecode::kIllegal)] = 1;
|
||||||
|
|
||||||
// Bytecode for CollectTypeProfile is only emitted when
|
|
||||||
// Type Information for DevTools is turned on.
|
|
||||||
scorecard[Bytecodes::ToByte(Bytecode::kCollectTypeProfile)] = 1;
|
|
||||||
|
|
||||||
// This bytecode is too inconvenient to test manually.
|
// This bytecode is too inconvenient to test manually.
|
||||||
scorecard[Bytecodes::ToByte(
|
scorecard[Bytecodes::ToByte(
|
||||||
Bytecode::kFindNonDefaultConstructorOrConstruct)] = 1;
|
Bytecode::kFindNonDefaultConstructorOrConstruct)] = 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user