[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:
Franziska Hinkelmann 2017-03-31 10:40:38 +02:00 committed by Commit Bot
parent 2a7ab87572
commit 961add84fd
11 changed files with 166 additions and 52 deletions

View File

@ -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;

View File

@ -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.

View File

@ -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);
}
}

View File

@ -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

View File

@ -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();
}

View File

@ -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,

View File

@ -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)) {

View File

@ -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(

View File

@ -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);

View File

@ -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";

View File

@ -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";
^