[type-profile] Collect types for parameters.
Add the source position to variables if they are parameters. Collect type information for parameters and return values. Index the types by their corresponding source position. For the types of return values, use the function end as source position. Sample output for a function with 2 parameters (at source position 252 and 258, and function end at 443) ************* Function: testFunction 252: Object number string number 258: undefined boolean undefined undefined 443: Object number string number ************* BUG=v8:5933 Change-Id: I3b8749afcac706c1834146abf1b5b4a3fd130fb6 Reviewed-on: https://chromium-review.googlesource.com/461919 Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Marja Hölttä <marja@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Commit-Queue: Franziska Hinkelmann <franzih@chromium.org> Cr-Commit-Position: refs/heads/master@{#44299}
This commit is contained in:
parent
2a7ab87572
commit
961add84fd
@ -1008,7 +1008,7 @@ Variable* Scope::Lookup(const AstRawString* name) {
|
||||
|
||||
Variable* DeclarationScope::DeclareParameter(
|
||||
const AstRawString* name, VariableMode mode, bool is_optional, bool is_rest,
|
||||
bool* is_duplicate, AstValueFactory* ast_value_factory) {
|
||||
bool* is_duplicate, AstValueFactory* ast_value_factory, int position) {
|
||||
DCHECK(!already_resolved_);
|
||||
DCHECK(is_function_scope() || is_module_scope());
|
||||
DCHECK(!has_rest_);
|
||||
@ -1025,6 +1025,7 @@ Variable* DeclarationScope::DeclareParameter(
|
||||
*is_duplicate = IsDeclaredParameter(name);
|
||||
}
|
||||
has_rest_ = is_rest;
|
||||
var->set_initializer_position(position);
|
||||
params_.Add(var, zone());
|
||||
if (name == ast_value_factory->arguments_string()) {
|
||||
has_arguments_parameter_ = true;
|
||||
|
@ -710,7 +710,7 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
|
||||
// expects all parameters to be declared and from left to right.
|
||||
Variable* DeclareParameter(const AstRawString* name, VariableMode mode,
|
||||
bool is_optional, bool is_rest, bool* is_duplicate,
|
||||
AstValueFactory* ast_value_factory);
|
||||
AstValueFactory* ast_value_factory, int position);
|
||||
|
||||
// Declares that a parameter with the name exists. Creates a Variable and
|
||||
// returns it if FLAG_preparser_scope_analysis is on.
|
||||
|
@ -910,26 +910,68 @@ InlineCacheState CollectTypeProfileNexus::StateFromFeedback() const {
|
||||
return MONOMORPHIC;
|
||||
}
|
||||
|
||||
void CollectTypeProfileNexus::Collect(Handle<Name> type, int position) {
|
||||
void CollectTypeProfileNexus::Collect(Handle<String> type, int position) {
|
||||
DCHECK_GT(position, 0);
|
||||
Isolate* isolate = GetIsolate();
|
||||
|
||||
Object* const feedback = GetFeedback();
|
||||
Handle<ArrayList> types;
|
||||
|
||||
// Map source position to collection of types
|
||||
Handle<UnseededNumberDictionary> types;
|
||||
|
||||
if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
|
||||
types = ArrayList::New(isolate, 1);
|
||||
types = UnseededNumberDictionary::NewEmpty(isolate);
|
||||
} else {
|
||||
types = Handle<ArrayList>(ArrayList::cast(feedback), isolate);
|
||||
types = Handle<UnseededNumberDictionary>(
|
||||
UnseededNumberDictionary::cast(feedback), isolate);
|
||||
}
|
||||
|
||||
Handle<Tuple2> entry = isolate->factory()->NewTuple2(
|
||||
type, Handle<Smi>(Smi::FromInt(position), isolate));
|
||||
Handle<ArrayList> types_for_position;
|
||||
|
||||
// TODO(franzih): Somehow sort this list. Either avoid duplicates
|
||||
// or use the common base type.
|
||||
SetFeedback(*ArrayList::Add(types, entry));
|
||||
if (types->Has(position)) {
|
||||
int entry = types->FindEntry(position);
|
||||
DCHECK(types->ValueAt(entry)->IsArrayList());
|
||||
types_for_position =
|
||||
Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)));
|
||||
} else {
|
||||
types_for_position = ArrayList::New(isolate, 1);
|
||||
}
|
||||
|
||||
types = UnseededNumberDictionary::Set(
|
||||
types, position, ArrayList::Add(types_for_position, type));
|
||||
SetFeedback(*types);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void PrintTypes(Handle<ArrayList> s) {
|
||||
for (int i = 0; i < s->Length(); i++) {
|
||||
Object* entry = s->Get(i);
|
||||
if (entry->IsString()) {
|
||||
PrintF("%s\n", String::cast(entry)->ToCString().get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SortTypes(Isolate* isolate,
|
||||
Handle<UnseededNumberDictionary> unsorted_types,
|
||||
std::map<int, Handle<ArrayList>>* types) {
|
||||
for (int index = UnseededNumberDictionary::kElementsStartIndex;
|
||||
index < unsorted_types->length();
|
||||
index += UnseededNumberDictionary::kEntrySize) {
|
||||
int key_index = index + UnseededNumberDictionary::kEntryKeyIndex;
|
||||
Object* key = unsorted_types->get(key_index);
|
||||
if (key->IsSmi()) {
|
||||
int value_index = index + UnseededNumberDictionary::kEntryValueIndex;
|
||||
Handle<ArrayList> types_for_position = Handle<ArrayList>(
|
||||
ArrayList::cast(unsorted_types->get(value_index)), isolate);
|
||||
|
||||
(*types)[Smi::cast(key)->value()] = types_for_position;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void CollectTypeProfileNexus::Print() const {
|
||||
Isolate* isolate = GetIsolate();
|
||||
|
||||
@ -939,17 +981,16 @@ void CollectTypeProfileNexus::Print() const {
|
||||
return;
|
||||
}
|
||||
|
||||
Handle<ArrayList> list;
|
||||
list = Handle<ArrayList>(ArrayList::cast(feedback), isolate);
|
||||
Handle<UnseededNumberDictionary> unsorted_types =
|
||||
Handle<UnseededNumberDictionary>(UnseededNumberDictionary::cast(feedback),
|
||||
isolate);
|
||||
|
||||
for (int i = 0; i < list->Length(); i++) {
|
||||
Handle<Object> maybe_entry = Handle<Object>(list->Get(i), isolate);
|
||||
DCHECK(maybe_entry->IsTuple2());
|
||||
Handle<Tuple2> entry = Handle<Tuple2>::cast(maybe_entry);
|
||||
Handle<String> type =
|
||||
Handle<String>(String::cast(entry->value1()), isolate);
|
||||
int position = Smi::cast(entry->value2())->value();
|
||||
PrintF("%d: %s\n", position, type->ToCString().get());
|
||||
std::map<int, Handle<ArrayList>> types;
|
||||
SortTypes(isolate, unsorted_types, &types);
|
||||
|
||||
for (const auto& entry : types) {
|
||||
PrintF("%d:\n", entry.first);
|
||||
PrintTypes(entry.second);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -760,7 +760,7 @@ class CollectTypeProfileNexus : public FeedbackNexus {
|
||||
}
|
||||
|
||||
// Add a type to the list of types.
|
||||
void Collect(Handle<Name> type, int position);
|
||||
void Collect(Handle<String> type, int position);
|
||||
|
||||
// Dump the types to stdout.
|
||||
// TODO(franzih): pass this information to the debugger protocol instead of
|
||||
|
@ -762,6 +762,16 @@ void BytecodeGenerator::GenerateBytecodeBody() {
|
||||
// Emit tracing call if requested to do so.
|
||||
if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter);
|
||||
|
||||
// Emit type profile call.
|
||||
if (info()->literal()->feedback_vector_spec()->HasTypeProfileSlot()) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
// Visit declarations within the function scope.
|
||||
VisitDeclarations(closure_scope()->declarations());
|
||||
|
||||
@ -2025,7 +2035,7 @@ void BytecodeGenerator::BuildReturn() {
|
||||
Runtime::kTraceExit, result);
|
||||
}
|
||||
if (info()->literal()->feedback_vector_spec()->HasTypeProfileSlot()) {
|
||||
builder()->CollectTypeProfile(info()->literal()->position());
|
||||
builder()->CollectTypeProfile(info()->literal()->return_position());
|
||||
}
|
||||
builder()->Return();
|
||||
}
|
||||
|
@ -16754,6 +16754,10 @@ template Handle<SeededNumberDictionary>
|
||||
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
|
||||
uint32_t>::NewEmpty(Isolate*, PretenureFlag pretenure);
|
||||
|
||||
template Handle<UnseededNumberDictionary>
|
||||
Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
|
||||
uint32_t>::NewEmpty(Isolate*, PretenureFlag pretenure);
|
||||
|
||||
template Handle<UnseededNumberDictionary>
|
||||
Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
|
||||
uint32_t>::New(Isolate*, int at_least_space_for,
|
||||
|
@ -192,7 +192,7 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
|
||||
bool is_optional = false;
|
||||
Variable* constructor_args = function_scope->DeclareParameter(
|
||||
constructor_args_name, TEMPORARY, is_optional, is_rest, &is_duplicate,
|
||||
ast_value_factory());
|
||||
ast_value_factory(), pos);
|
||||
|
||||
ZoneList<Expression*>* args =
|
||||
new (zone()) ZoneList<Expression*>(1, zone());
|
||||
@ -707,8 +707,9 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
|
||||
bool is_duplicate;
|
||||
bool is_rest = false;
|
||||
bool is_optional = false;
|
||||
auto var = scope->DeclareParameter(name, VAR, is_optional, is_rest,
|
||||
&is_duplicate, ast_value_factory());
|
||||
auto var =
|
||||
scope->DeclareParameter(name, VAR, is_optional, is_rest,
|
||||
&is_duplicate, ast_value_factory(), beg_pos);
|
||||
DCHECK(!is_duplicate);
|
||||
var->AllocateTo(VariableLocation::PARAMETER, 0);
|
||||
|
||||
@ -892,7 +893,7 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info,
|
||||
ParserFormalParameters formals(scope);
|
||||
{
|
||||
// Parsing patterns as variable reference expression creates
|
||||
// NewUnresolved references in current scope. Entrer arrow function
|
||||
// NewUnresolved references in current scope. Enter arrow function
|
||||
// scope for formal parameter parsing.
|
||||
BlockState block_state(&scope_, scope);
|
||||
if (Check(Token::LPAREN)) {
|
||||
|
@ -133,16 +133,18 @@ class Parser;
|
||||
struct ParserFormalParameters : FormalParametersBase {
|
||||
struct Parameter : public ZoneObject {
|
||||
Parameter(const AstRawString* name, Expression* pattern,
|
||||
Expression* initializer, int initializer_end_position,
|
||||
bool is_rest)
|
||||
Expression* initializer, int position,
|
||||
int initializer_end_position, bool is_rest)
|
||||
: name(name),
|
||||
pattern(pattern),
|
||||
initializer(initializer),
|
||||
position(position),
|
||||
initializer_end_position(initializer_end_position),
|
||||
is_rest(is_rest) {}
|
||||
const AstRawString* name;
|
||||
Expression* pattern;
|
||||
Expression* initializer;
|
||||
int position;
|
||||
int initializer_end_position;
|
||||
bool is_rest;
|
||||
Parameter* next_parameter = nullptr;
|
||||
@ -1081,9 +1083,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
||||
const AstRawString* name = has_simple_name
|
||||
? pattern->AsVariableProxy()->raw_name()
|
||||
: ast_value_factory()->empty_string();
|
||||
auto parameter =
|
||||
new (parameters->scope->zone()) ParserFormalParameters::Parameter(
|
||||
name, pattern, initializer, initializer_end_position, is_rest);
|
||||
auto parameter = new (parameters->scope->zone())
|
||||
ParserFormalParameters::Parameter(name, pattern, initializer,
|
||||
scanner()->location().beg_pos,
|
||||
initializer_end_position, is_rest);
|
||||
|
||||
parameters->params.Add(parameter);
|
||||
}
|
||||
@ -1103,7 +1106,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
||||
scope->DeclareParameter(
|
||||
is_simple ? parameter->name : ast_value_factory()->empty_string(),
|
||||
is_simple ? VAR : TEMPORARY, is_optional, parameter->is_rest,
|
||||
&is_duplicate, ast_value_factory());
|
||||
&is_duplicate, ast_value_factory(), parameter->position);
|
||||
if (is_duplicate &&
|
||||
classifier()->is_valid_formal_parameter_list_without_duplicates()) {
|
||||
classifier()->RecordDuplicateFormalParameterError(
|
||||
|
@ -707,7 +707,7 @@ RUNTIME_FUNCTION(Runtime_CollectTypeProfile) {
|
||||
|
||||
DCHECK(FLAG_type_profile);
|
||||
|
||||
Handle<Name> type = Object::TypeOf(isolate, value);
|
||||
Handle<String> type = Object::TypeOf(isolate, value);
|
||||
if (value->IsJSReceiver()) {
|
||||
Handle<JSReceiver> object = Handle<JSReceiver>::cast(value);
|
||||
type = JSReceiver::GetConstructorName(object);
|
||||
|
@ -60,4 +60,11 @@ testReturnOfNonVariable();
|
||||
function never_call() {}
|
||||
%PrintTypeProfile(never_call);
|
||||
|
||||
throw "throw otherwise test fails with --stress-opt";
|
||||
function check_param(a, bbb, ccccccccc, dddddddddddddddd) {
|
||||
//nothing
|
||||
}
|
||||
check_param(2, 'foo', {}, new MyClass());
|
||||
%PrintTypeProfile(check_param);
|
||||
|
||||
|
||||
throw "end";
|
||||
|
@ -1,26 +1,73 @@
|
||||
Function: testFunction
|
||||
246: Object
|
||||
246: number
|
||||
246: string
|
||||
246: number
|
||||
247:
|
||||
Object
|
||||
number
|
||||
string
|
||||
number
|
||||
254:
|
||||
undefined
|
||||
boolean
|
||||
undefined
|
||||
undefined
|
||||
443:
|
||||
Object
|
||||
number
|
||||
string
|
||||
number
|
||||
|
||||
Function: testFunction
|
||||
246: Object
|
||||
246: number
|
||||
246: string
|
||||
246: number
|
||||
246: undefined
|
||||
246: string
|
||||
246: Object
|
||||
246: Object
|
||||
246: MyClass
|
||||
247:
|
||||
Object
|
||||
number
|
||||
string
|
||||
number
|
||||
undefined
|
||||
string
|
||||
Object
|
||||
Object
|
||||
MyClass
|
||||
254:
|
||||
undefined
|
||||
boolean
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
boolean
|
||||
boolean
|
||||
undefined
|
||||
undefined
|
||||
443:
|
||||
Object
|
||||
number
|
||||
string
|
||||
number
|
||||
undefined
|
||||
string
|
||||
Object
|
||||
Object
|
||||
MyClass
|
||||
|
||||
Function: try_finally
|
||||
956: string
|
||||
1038:
|
||||
string
|
||||
|
||||
Function: fall_off
|
||||
1105: undefined
|
||||
1122:
|
||||
undefined
|
||||
|
||||
*%(basename)s:63: throw otherwise test fails with --stress-opt
|
||||
throw "throw otherwise test fails with --stress-opt";
|
||||
Function: check_param
|
||||
1272:
|
||||
number
|
||||
1275:
|
||||
string
|
||||
1280:
|
||||
Object
|
||||
1291:
|
||||
MyClass
|
||||
1323:
|
||||
undefined
|
||||
|
||||
|
||||
*%(basename)s:70: end
|
||||
throw "end";
|
||||
^
|
||||
|
Loading…
Reference in New Issue
Block a user