Reland of "Store SharedFunctionInfos of a Script in a FixedArray indexed by their ID"

Original CL description:
> Store SharedFunctionInfos of a Script in a FixedArray indexed by their ID
>
> Now that SharedFunctionInfos have a unique ID (and the IDs are dense),
> we can use them as an index into an array, instead of using a
> WeakFixedArray where we have to do a linear scan.
>
> Hooking up liveedit is a bit more involved, see
> https://docs.google.com/presentation/d/1FtNa3U7WsF5bPhY9uGoJG5Y9hnz5VBDabfOWpb4unWI/edit
> for an overview
>
> BUG=v8:5589
> R=verwaest@chromium.org,jgruber@chromium.org
>
> Review-Url: https://codereview.chromium.org/2547483002

BUG=v8:5589
TBR=verwaest@chromium.org,jgruber@chromium.org

Review-Url: https://codereview.chromium.org/2577063002
Cr-Commit-Position: refs/heads/master@{#41734}
This commit is contained in:
jochen 2016-12-15 09:19:55 -08:00 committed by Commit bot
parent c131dd9561
commit 4f2cb8fe82
24 changed files with 257 additions and 156 deletions

View File

@ -595,8 +595,11 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
Handle<String> source = factory->NewStringFromStaticChars("() {}");
Handle<Script> script = factory->NewScript(source);
script->set_type(Script::TYPE_NATIVE);
Handle<FixedArray> infos = factory->NewFixedArray(2);
script->set_shared_function_infos(*infos);
empty_function->shared()->set_start_position(0);
empty_function->shared()->set_end_position(source->length());
empty_function->shared()->set_function_literal_id(1);
empty_function->shared()->DontAdaptArguments();
SharedFunctionInfo::SetScript(handle(empty_function->shared()), script);

View File

@ -460,12 +460,29 @@ bool CompileUnoptimizedCode(CompilationInfo* info) {
return true;
}
void EnsureSharedFunctionInfosArrayOnScript(ParseInfo* info) {
DCHECK(info->is_toplevel());
DCHECK(!info->script().is_null());
if (info->script()->shared_function_infos()->length() > 0) {
DCHECK_EQ(info->script()->shared_function_infos()->length(),
info->max_function_literal_id() + 1);
return;
}
Isolate* isolate = info->isolate();
Handle<FixedArray> infos(
isolate->factory()->NewFixedArray(info->max_function_literal_id() + 1));
info->script()->set_shared_function_infos(*infos);
}
MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(CompilationInfo* info) {
VMState<COMPILER> state(info->isolate());
PostponeInterruptsScope postpone(info->isolate());
// Parse and update CompilationInfo with the results.
if (!parsing::ParseAny(info->parse_info())) return MaybeHandle<Code>();
if (info->parse_info()->is_toplevel()) {
EnsureSharedFunctionInfosArrayOnScript(info->parse_info());
}
DCHECK_EQ(info->shared_info()->language_mode(),
info->literal()->language_mode());
@ -970,6 +987,8 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) {
return Handle<SharedFunctionInfo>::null();
}
EnsureSharedFunctionInfosArrayOnScript(parse_info);
FunctionLiteral* lit = parse_info->literal();
// Measure how long it takes to do the compilation; only take the
@ -1032,6 +1051,7 @@ bool Compiler::Analyze(ParseInfo* info) {
bool Compiler::ParseAndAnalyze(ParseInfo* info) {
if (!parsing::ParseAny(info)) return false;
if (info->is_toplevel()) EnsureSharedFunctionInfosArrayOnScript(info);
if (!Compiler::Analyze(info)) return false;
DCHECK_NOT_NULL(info->literal());
DCHECK_NOT_NULL(info->scope());
@ -1152,8 +1172,9 @@ MaybeHandle<JSArray> Compiler::CompileForLiveEdit(Handle<Script> script) {
// In order to ensure that live edit function info collection finds the newly
// generated shared function infos, clear the script's list temporarily
// and restore it at the end of this method.
Handle<Object> old_function_infos(script->shared_function_infos(), isolate);
script->set_shared_function_infos(Smi::kZero);
Handle<FixedArray> old_function_infos(script->shared_function_infos(),
isolate);
script->set_shared_function_infos(isolate->heap()->empty_fixed_array());
// Start a compilation.
Zone zone(isolate->allocator(), ZONE_NAME);
@ -1563,15 +1584,7 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
MaybeHandle<SharedFunctionInfo> maybe_existing;
// Find any previously allocated shared function info for the given literal.
if (outer_info->shared_info()->never_compiled()) {
// On the first compile, there are no existing shared function info for
// inner functions yet, so do not try to find them. All bets are off for
// live edit though.
SLOW_DCHECK(script->FindSharedFunctionInfo(literal).is_null() ||
isolate->debug()->live_edit_enabled());
} else {
maybe_existing = script->FindSharedFunctionInfo(literal);
}
maybe_existing = script->FindSharedFunctionInfo(isolate, literal);
// We found an existing shared function info. If it has any sort of code
// attached, don't worry about compiling and simply return it. Otherwise,
@ -1594,11 +1607,6 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
result =
isolate->factory()->NewSharedFunctionInfoForLiteral(literal, script);
result->set_is_toplevel(false);
// If the outer function has been compiled before, we cannot be sure that
// shared function info for this function literal has been created for the
// first time. It may have already been compiled previously.
result->set_never_compiled(outer_info->shared_info()->never_compiled());
}
Zone zone(isolate->allocator(), ZONE_NAME);

View File

@ -142,7 +142,6 @@ HCompilationJob::Status HCompilationJob::PrepareJobImpl() {
}
}
DCHECK(info()->shared_info()->has_deoptimization_support());
DCHECK(!info()->shared_info()->never_compiled());
// Check the whitelist for Crankshaft.
if (!info()->shared_info()->PassesFilter(FLAG_hydrogen_filter)) {

View File

@ -1244,7 +1244,7 @@ bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) {
// cover this, because the given function might have been inlined into code
// for which no JSFunction exists.
{
SharedFunctionInfo::Iterator iterator(isolate_);
SharedFunctionInfo::GlobalIterator iterator(isolate_);
while (SharedFunctionInfo* shared = iterator.Next()) {
shared->ClearCodeFromOptimizedCodeMap();
}
@ -1335,16 +1335,11 @@ void FindBreakablePositions(Handle<DebugInfo> debug_info, int start_position,
bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position,
int end_position, std::set<int>* positions) {
while (true) {
if (!script->shared_function_infos()->IsWeakFixedArray()) return false;
WeakFixedArray* infos =
WeakFixedArray::cast(script->shared_function_infos());
HandleScope scope(isolate_);
List<Handle<SharedFunctionInfo>> candidates;
{
WeakFixedArray::Iterator iterator(infos);
SharedFunctionInfo* info;
while ((info = iterator.Next<SharedFunctionInfo>())) {
SharedFunctionInfo::ScriptIterator iterator(script);
for (SharedFunctionInfo* info = iterator.Next(); info != nullptr;
info = iterator.Next()) {
if (info->end_position() < start_position ||
info->start_position() >= end_position) {
continue;
@ -1353,7 +1348,6 @@ bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position,
if (!info->HasDebugCode() && !info->allows_lazy_compilation()) continue;
candidates.Add(i::handle(info));
}
}
bool was_compiled = false;
for (int i = 0; i < candidates.length(); ++i) {
@ -1462,15 +1456,14 @@ Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
// find the inner most function containing this position.
// If there is no shared function info for this script at all, there is
// no point in looking for it by walking the heap.
if (!script->shared_function_infos()->IsWeakFixedArray()) break;
SharedFunctionInfo* shared;
{
SharedFunctionInfoFinder finder(position);
WeakFixedArray::Iterator iterator(script->shared_function_infos());
SharedFunctionInfo* candidate;
while ((candidate = iterator.Next<SharedFunctionInfo>())) {
finder.NewCandidate(candidate);
SharedFunctionInfo::ScriptIterator iterator(script);
for (SharedFunctionInfo* info = iterator.Next(); info != nullptr;
info = iterator.Next()) {
finder.NewCandidate(info);
}
shared = finder.Result();
if (shared == NULL) break;

View File

@ -604,12 +604,9 @@ static int GetArrayLength(Handle<JSArray> array) {
return Smi::cast(length)->value();
}
void FunctionInfoWrapper::SetInitialProperties(Handle<String> name,
int start_position,
int end_position, int param_num,
int literal_count,
int parent_index) {
void FunctionInfoWrapper::SetInitialProperties(
Handle<String> name, int start_position, int end_position, int param_num,
int literal_count, int parent_index, int function_literal_id) {
HandleScope scope(isolate());
this->SetField(kFunctionNameOffset_, name);
this->SetSmiValueField(kStartPositionOffset_, start_position);
@ -617,6 +614,7 @@ void FunctionInfoWrapper::SetInitialProperties(Handle<String> name,
this->SetSmiValueField(kParamNumOffset_, param_num);
this->SetSmiValueField(kLiteralNumOffset_, literal_count);
this->SetSmiValueField(kParentIndexOffset_, parent_index);
this->SetSmiValueField(kFunctionLiteralIdOffset_, function_literal_id);
}
void FunctionInfoWrapper::SetSharedFunctionInfo(
@ -1038,15 +1036,36 @@ void LiveEdit::ReplaceFunctionCode(
isolate->compilation_cache()->Remove(shared_info);
}
void LiveEdit::FunctionSourceUpdated(Handle<JSArray> shared_info_array) {
void LiveEdit::FunctionSourceUpdated(Handle<JSArray> shared_info_array,
int new_function_literal_id) {
SharedInfoWrapper shared_info_wrapper(shared_info_array);
Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
shared_info->set_function_literal_id(new_function_literal_id);
DeoptimizeDependentFunctions(*shared_info);
shared_info_array->GetIsolate()->compilation_cache()->Remove(shared_info);
}
void LiveEdit::FixupScript(Handle<Script> script, int max_function_literal_id) {
Isolate* isolate = script->GetIsolate();
Handle<FixedArray> old_infos(script->shared_function_infos(), isolate);
Handle<FixedArray> new_infos(
isolate->factory()->NewFixedArray(max_function_literal_id + 1));
script->set_shared_function_infos(*new_infos);
SharedFunctionInfo::ScriptIterator iterator(isolate, old_infos);
while (SharedFunctionInfo* shared = iterator.Next()) {
// We can't use SharedFunctionInfo::SetScript(info, undefined_value()) here,
// as we severed the link from the Script to the SharedFunctionInfo above.
Handle<SharedFunctionInfo> info(shared, isolate);
info->set_script(isolate->heap()->undefined_value());
Handle<Object> new_noscript_list = WeakFixedArray::Add(
isolate->factory()->noscript_shared_function_infos(), info);
isolate->heap()->SetRootNoScriptSharedFunctionInfos(*new_noscript_list);
// Put the SharedFunctionInfo at its new, correct location.
SharedFunctionInfo::SetScript(info, script);
}
}
void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
Handle<Object> script_handle) {
@ -1173,6 +1192,10 @@ static Handle<Script> CreateScriptCopy(Handle<Script> original) {
copy->set_eval_from_shared(original->eval_from_shared());
copy->set_eval_from_position(original->eval_from_position());
Handle<FixedArray> infos(isolate->factory()->NewFixedArray(
original->shared_function_infos()->length()));
copy->set_shared_function_infos(*infos);
// Copy all the flags, but clear compilation state.
copy->set_flags(original->flags());
copy->set_compilation_state(Script::COMPILATION_STATE_INITIAL);
@ -1180,7 +1203,6 @@ static Handle<Script> CreateScriptCopy(Handle<Script> original) {
return copy;
}
Handle<Object> LiveEdit::ChangeScriptSource(Handle<Script> original_script,
Handle<String> new_source,
Handle<Object> old_script_name) {
@ -1856,10 +1878,8 @@ void LiveEditFunctionTracker::VisitFunctionLiteral(FunctionLiteral* node) {
// Recurse using the regular traversal.
AstTraversalVisitor::VisitFunctionLiteral(node);
// FunctionDone are called in post-order.
// TODO(jgruber): If required, replace the (linear cost)
// FindSharedFunctionInfo call with a more efficient implementation.
Handle<SharedFunctionInfo> info =
script_->FindSharedFunctionInfo(node).ToHandleChecked();
script_->FindSharedFunctionInfo(isolate_, node).ToHandleChecked();
FunctionDone(info, node->scope());
}
@ -1869,7 +1889,7 @@ void LiveEditFunctionTracker::FunctionStarted(FunctionLiteral* fun) {
info.SetInitialProperties(fun->name(), fun->start_position(),
fun->end_position(), fun->parameter_count(),
fun->materialized_literal_count(),
current_parent_index_);
current_parent_index_, fun->function_literal_id());
current_parent_index_ = len_;
SetElementSloppy(result_, len_, info.GetJSArray());
len_++;

View File

@ -83,7 +83,10 @@ class LiveEdit : AllStatic {
static void ReplaceFunctionCode(Handle<JSArray> new_compile_info_array,
Handle<JSArray> shared_info_array);
static void FunctionSourceUpdated(Handle<JSArray> shared_info_array);
static void FixupScript(Handle<Script> script, int max_function_literal_id);
static void FunctionSourceUpdated(Handle<JSArray> shared_info_array,
int new_function_literal_id);
// Updates script field in FunctionSharedInfo.
static void SetFunctionScript(Handle<JSValue> function_wrapper,
@ -278,7 +281,7 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
void SetInitialProperties(Handle<String> name, int start_position,
int end_position, int param_num, int literal_count,
int parent_index);
int parent_index, int function_literal_id);
void SetFunctionScopeInfo(Handle<Object> scope_info_array) {
this->SetField(kFunctionScopeInfoOffset_, scope_info_array);
@ -311,7 +314,8 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
static const int kParentIndexOffset_ = 5;
static const int kSharedFunctionInfoOffset_ = 6;
static const int kLiteralNumOffset_ = 7;
static const int kSize_ = 8;
static const int kFunctionLiteralIdOffset_ = 8;
static const int kSize_ = 9;
friend class JSArrayBasedStruct<FunctionInfoWrapper>;
};

View File

@ -29,6 +29,7 @@
var FindScriptSourcePosition = global.Debug.findScriptSourcePosition;
var GlobalArray = global.Array;
var MathFloor = global.Math.floor;
var MathMax = global.Math.max;
var SyntaxError = global.SyntaxError;
// -------------------------------------------------------------------
@ -75,6 +76,10 @@
}
throw failure;
}
var max_function_literal_id = new_compile_info.reduce(
(max, info) => MathMax(max, info.function_literal_id), 0);
var root_new_node = BuildCodeInfoTree(new_compile_info);
// Link recompiled script data with other data.
@ -177,8 +182,7 @@
// Update the script text and create a new script representing an old
// version of the script.
old_script = %LiveEditReplaceScript(script, new_source,
old_script_name);
old_script = %LiveEditReplaceScript(script, new_source, old_script_name);
var link_to_old_script_report = new GlobalArray();
change_log.push( { linked_to_old_script: link_to_old_script_report } );
@ -192,12 +196,6 @@
preview_description.created_script_name = old_script_name;
}
// Link to an actual script all the functions that we are going to use.
for (var i = 0; i < link_to_original_script_list.length; i++) {
%LiveEditFunctionSetScript(
link_to_original_script_list[i].info.shared_function_info, script);
}
for (var i = 0; i < replace_code_list.length; i++) {
PatchFunctionCode(replace_code_list[i], change_log);
}
@ -212,13 +210,25 @@
position_patch_report);
if (update_positions_list[i].live_shared_function_infos) {
update_positions_list[i].live_shared_function_infos.
forEach(function (info) {
%LiveEditFunctionSourceUpdated(info.raw_array);
var new_function_literal_id =
update_positions_list[i]
.corresponding_node.info.function_literal_id;
update_positions_list[i].live_shared_function_infos.forEach(function(
info) {
%LiveEditFunctionSourceUpdated(
info.raw_array, new_function_literal_id);
});
}
}
%LiveEditFixupScript(script, max_function_literal_id);
// Link all the functions we're going to use to an actual script.
for (var i = 0; i < link_to_original_script_list.length; i++) {
%LiveEditFunctionSetScript(
link_to_original_script_list[i].info.shared_function_info, script);
}
preview_description.updated = true;
return preview_description;
}
@ -658,6 +668,8 @@
old_children[old_index].corresponding_node = UNDEFINED;
old_node.status = FunctionStatus.CHANGED;
}
} else {
ProcessNode(old_children[old_index], new_children[new_index]);
}
} else {
old_children[old_index].status = FunctionStatus.DAMAGED;
@ -761,6 +773,7 @@
this.scope_info = raw_array[4];
this.outer_index = raw_array[5];
this.shared_function_info = raw_array[6];
this.function_literal_id = raw_array[8];
this.next_sibling_index = null;
this.raw_array = raw_array;
}

View File

@ -167,7 +167,6 @@ Handle<FixedArray> Factory::NewFixedArrayWithHoles(int size,
FixedArray);
}
Handle<FixedArray> Factory::NewUninitializedFixedArray(int size) {
CALL_HEAP_FUNCTION(
isolate(),
@ -1059,7 +1058,7 @@ Handle<Script> Factory::NewScript(Handle<String> source) {
script->set_line_ends(heap->undefined_value());
script->set_eval_from_shared(heap->undefined_value());
script->set_eval_from_position(0);
script->set_shared_function_infos(Smi::kZero);
script->set_shared_function_infos(*empty_fixed_array(), SKIP_WRITE_BARRIER);
script->set_flags(0);
heap->set_script_list(*WeakFixedArray::Add(script_list(), script));

View File

@ -5800,8 +5800,6 @@ void Heap::CompactWeakFixedArrays() {
WeakFixedArray* array = WeakFixedArray::cast(prototype_users);
array->Compact<JSObject::PrototypeRegistryCompactionCallback>();
}
} else if (o->IsScript()) {
CompactWeakFixedArray(Script::cast(o)->shared_function_infos());
}
}
CompactWeakFixedArray(noscript_shared_function_infos());

View File

@ -441,10 +441,8 @@ void ObjectStatsCollector::RecordJSCollectionDetails(JSObject* obj) {
}
void ObjectStatsCollector::RecordScriptDetails(Script* obj) {
Object* infos = WeakFixedArray::cast(obj->shared_function_infos());
if (infos->IsWeakFixedArray())
RecordFixedArrayHelper(obj, WeakFixedArray::cast(infos),
SHARED_FUNCTION_INFOS_SUB_TYPE, 0);
FixedArray* infos = FixedArray::cast(obj->shared_function_infos());
RecordFixedArrayHelper(obj, infos, SHARED_FUNCTION_INFOS_SUB_TYPE, 0);
}
void ObjectStatsCollector::RecordMapDetails(Map* map_obj) {

View File

@ -363,7 +363,7 @@ utils.InstallGetter(GlobalPromise, speciesSymbol, PromiseSpecies);
%SetCode(GlobalPromise.prototype.catch, PromiseCatch);
%InstallToContext([
"promise_catch", PromiseCatch,
"promise_catch", GlobalPromise.prototype.catch,
"promise_create", PromiseCreate,
"promise_has_user_defined_reject_handler", PromiseHasUserDefinedRejectHandler,
"promise_reject", DoRejectPromise,

View File

@ -5962,7 +5962,7 @@ ACCESSORS_CHECKED(Script, eval_from_shared, Object, kEvalFromSharedOffset,
this->type() != TYPE_WASM)
SMI_ACCESSORS_CHECKED(Script, eval_from_position, kEvalFromPositionOffset,
this->type() != TYPE_WASM)
ACCESSORS(Script, shared_function_infos, Object, kSharedFunctionInfosOffset)
ACCESSORS(Script, shared_function_infos, FixedArray, kSharedFunctionInfosOffset)
SMI_ACCESSORS(Script, flags, kFlagsOffset)
ACCESSORS(Script, source_url, Object, kSourceUrlOffset)
ACCESSORS(Script, source_mapping_url, Object, kSourceMappingUrlOffset)
@ -6078,8 +6078,6 @@ BOOL_ACCESSORS(SharedFunctionInfo,
kHasDuplicateParameters)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, asm_function, kIsAsmFunction)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, deserialized, kDeserialized)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, never_compiled,
kNeverCompiled)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_declaration,
kIsDeclaration)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, marked_for_tier_up,
@ -6300,8 +6298,6 @@ void SharedFunctionInfo::ReplaceCode(Code* value) {
#endif // DEBUG
set_code(value);
if (is_compiled()) set_never_compiled(false);
}
bool SharedFunctionInfo::IsInterpreted() const {

View File

@ -13645,23 +13645,16 @@ Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
return result;
}
MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
FunctionLiteral* fun) {
WeakFixedArray::Iterator iterator(shared_function_infos());
SharedFunctionInfo* shared;
while ((shared = iterator.Next<SharedFunctionInfo>())) {
if (fun->function_token_position() == shared->function_token_position() &&
fun->start_position() == shared->start_position() &&
fun->end_position() == shared->end_position()) {
DCHECK_EQ(fun->function_literal_id(), shared->function_literal_id());
return Handle<SharedFunctionInfo>(shared);
}
DCHECK_NE(fun->function_literal_id(), shared->function_literal_id());
}
Isolate* isolate, FunctionLiteral* fun) {
DCHECK_NE(fun->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
DCHECK_LT(fun->function_literal_id(), shared_function_infos()->length());
Object* shared = shared_function_infos()->get(fun->function_literal_id());
if (shared->IsUndefined(isolate) || WeakCell::cast(shared)->cleared()) {
return MaybeHandle<SharedFunctionInfo>();
}
return handle(SharedFunctionInfo::cast(WeakCell::cast(shared)->value()));
}
Script::Iterator::Iterator(Isolate* isolate)
: iterator_(isolate->heap()->script_list()) {}
@ -13669,31 +13662,51 @@ Script::Iterator::Iterator(Isolate* isolate)
Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
SharedFunctionInfo::ScriptIterator::ScriptIterator(Handle<Script> script)
: ScriptIterator(script->GetIsolate(),
handle(script->shared_function_infos())) {}
SharedFunctionInfo::Iterator::Iterator(Isolate* isolate)
: script_iterator_(isolate),
sfi_iterator_(isolate->heap()->noscript_shared_function_infos()) {}
SharedFunctionInfo::ScriptIterator::ScriptIterator(
Isolate* isolate, Handle<FixedArray> shared_function_infos)
: isolate_(isolate),
shared_function_infos_(shared_function_infos),
index_(0) {}
bool SharedFunctionInfo::Iterator::NextScript() {
Script* script = script_iterator_.Next();
if (script == NULL) return false;
sfi_iterator_.Reset(script->shared_function_infos());
return true;
SharedFunctionInfo* SharedFunctionInfo::ScriptIterator::Next() {
while (index_ < shared_function_infos_->length()) {
Object* raw = shared_function_infos_->get(index_++);
if (raw->IsUndefined(isolate_) || WeakCell::cast(raw)->cleared()) continue;
return SharedFunctionInfo::cast(WeakCell::cast(raw)->value());
}
return nullptr;
}
void SharedFunctionInfo::ScriptIterator::Reset(Handle<Script> script) {
shared_function_infos_ = handle(script->shared_function_infos());
index_ = 0;
}
SharedFunctionInfo* SharedFunctionInfo::Iterator::Next() {
do {
SharedFunctionInfo* next = sfi_iterator_.Next<SharedFunctionInfo>();
if (next != NULL) return next;
} while (NextScript());
return NULL;
SharedFunctionInfo::GlobalIterator::GlobalIterator(Isolate* isolate)
: script_iterator_(isolate),
noscript_sfi_iterator_(isolate->heap()->noscript_shared_function_infos()),
sfi_iterator_(handle(script_iterator_.Next(), isolate)) {}
SharedFunctionInfo* SharedFunctionInfo::GlobalIterator::Next() {
SharedFunctionInfo* next = noscript_sfi_iterator_.Next<SharedFunctionInfo>();
if (next != nullptr) return next;
for (;;) {
next = sfi_iterator_.Next();
if (next != nullptr) return next;
Script* next_script = script_iterator_.Next();
if (next_script == nullptr) return nullptr;
sfi_iterator_.Reset(handle(next_script));
}
}
void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
Handle<Object> script_object) {
DCHECK_NE(shared->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
if (shared->script() == *script_object) return;
Isolate* isolate = shared->GetIsolate();
@ -13701,13 +13714,22 @@ void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
// the shared function info may be temporarily in two lists.
// This is okay because the gc-time processing of these lists can tolerate
// duplicates.
Handle<Object> list;
if (script_object->IsScript()) {
Handle<Script> script = Handle<Script>::cast(script_object);
list = handle(script->shared_function_infos(), isolate);
} else {
list = isolate->factory()->noscript_shared_function_infos();
Handle<FixedArray> list = handle(script->shared_function_infos(), isolate);
#ifdef DEBUG
DCHECK_LT(shared->function_literal_id(), list->length());
if (list->get(shared->function_literal_id())->IsWeakCell() &&
!WeakCell::cast(list->get(shared->function_literal_id()))->cleared()) {
DCHECK(
WeakCell::cast(list->get(shared->function_literal_id()))->value() ==
*shared);
}
#endif
Handle<WeakCell> cell = isolate->factory()->NewWeakCell(shared);
list->set(shared->function_literal_id(), *cell);
} else {
Handle<Object> list = isolate->factory()->noscript_shared_function_infos();
#ifdef DEBUG
if (FLAG_enable_slow_asserts) {
@ -13718,22 +13740,26 @@ void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
}
}
#endif // DEBUG
list = WeakFixedArray::Add(list, shared);
if (script_object->IsScript()) {
Handle<Script> script = Handle<Script>::cast(script_object);
script->set_shared_function_infos(*list);
} else {
isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
}
// Remove shared function info from old script's list.
if (shared->script()->IsScript()) {
// Remove shared function info from old script's list.
Script* old_script = Script::cast(shared->script());
if (old_script->shared_function_infos()->IsWeakFixedArray()) {
WeakFixedArray* list =
WeakFixedArray::cast(old_script->shared_function_infos());
list->Remove(shared);
// Due to liveedit, it might happen that the old_script doesn't know
// about the SharedFunctionInfo, so we have to guard against that.
Handle<FixedArray> infos(old_script->shared_function_infos(), isolate);
if (shared->function_literal_id() < infos->length()) {
Object* raw = old_script->shared_function_infos()->get(
shared->function_literal_id());
if (!raw->IsWeakCell() || WeakCell::cast(raw)->value() == *shared) {
old_script->shared_function_infos()->set(
shared->function_literal_id(), isolate->heap()->undefined_value());
}
}
} else {
// Remove shared function info from root array.
@ -13998,7 +14024,6 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
shared_info->set_uses_arguments(lit->scope()->arguments() != NULL);
shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
shared_info->set_is_function(lit->is_function());
shared_info->set_never_compiled(true);
shared_info->set_kind(lit->kind());
if (!IsConstructable(lit->kind(), lit->language_mode())) {
shared_info->SetConstructStub(

View File

@ -7127,7 +7127,7 @@ class Script: public Struct {
// [shared_function_infos]: weak fixed array containing all shared
// function infos created from this script.
DECL_ACCESSORS(shared_function_infos, Object)
DECL_ACCESSORS(shared_function_infos, FixedArray)
// [flags]: Holds an exciting bitfield.
DECL_INT_ACCESSORS(flags)
@ -7212,7 +7212,8 @@ class Script: public Struct {
// Look through the list of existing shared function infos to find one
// that matches the function literal. Return empty handle if not found.
MaybeHandle<SharedFunctionInfo> FindSharedFunctionInfo(FunctionLiteral* fun);
MaybeHandle<SharedFunctionInfo> FindSharedFunctionInfo(Isolate* isolate,
FunctionLiteral* fun);
// Iterate over all script objects on the heap.
class Iterator {
@ -7740,9 +7741,6 @@ class SharedFunctionInfo: public HeapObject {
// Indicates that the the shared function info is deserialized from cache.
DECL_BOOLEAN_ACCESSORS(deserialized)
// Indicates that the the shared function info has never been compiled before.
DECL_BOOLEAN_ACCESSORS(never_compiled)
// Whether this function was created from a FunctionDeclaration.
DECL_BOOLEAN_ACCESSORS(is_declaration)
@ -7830,19 +7828,35 @@ class SharedFunctionInfo: public HeapObject {
void ResetForNewContext(int new_ic_age);
// Iterate over all shared function infos.
class Iterator {
// Iterate over all shared function infos in a given script.
class ScriptIterator {
public:
explicit Iterator(Isolate* isolate);
explicit ScriptIterator(Handle<Script> script);
ScriptIterator(Isolate* isolate, Handle<FixedArray> shared_function_infos);
SharedFunctionInfo* Next();
// Reset the iterator to run on |script|.
void Reset(Handle<Script> script);
private:
Isolate* isolate_;
Handle<FixedArray> shared_function_infos_;
int index_;
DISALLOW_COPY_AND_ASSIGN(ScriptIterator);
};
// Iterate over all shared function infos on the heap.
class GlobalIterator {
public:
explicit GlobalIterator(Isolate* isolate);
SharedFunctionInfo* Next();
private:
bool NextScript();
Script::Iterator script_iterator_;
WeakFixedArray::Iterator sfi_iterator_;
WeakFixedArray::Iterator noscript_sfi_iterator_;
SharedFunctionInfo::ScriptIterator sfi_iterator_;
DisallowHeapAllocation no_gc_;
DISALLOW_COPY_AND_ASSIGN(Iterator);
DISALLOW_COPY_AND_ASSIGN(GlobalIterator);
};
DECLARE_CAST(SharedFunctionInfo)
@ -8002,7 +8016,7 @@ class SharedFunctionInfo: public HeapObject {
kAllowLazyCompilation,
kMarkedForTierUp,
kOptimizationDisabled,
kNeverCompiled,
kIsClassFieldInitializer,
kNative,
kStrictModeFunction,
kUsesArguments,
@ -8024,7 +8038,6 @@ class SharedFunctionInfo: public HeapObject {
kIsDeclaration,
kIsAsmWasmBroken,
kRequiresClassFieldInit,
kIsClassFieldInitializer,
kCompilerHintsCount, // Pseudo entry
};
// kFunctionKind has to be byte-aligned

View File

@ -27,6 +27,7 @@ ParseInfo::ParseInfo(Zone* zone)
start_position_(0),
end_position_(0),
function_literal_id_(FunctionLiteral::kIdTypeInvalid),
max_function_literal_id_(FunctionLiteral::kIdTypeInvalid),
isolate_(nullptr),
cached_data_(nullptr),
ast_value_factory_(nullptr),

View File

@ -154,6 +154,11 @@ class V8_EXPORT_PRIVATE ParseInfo {
function_literal_id_ = function_literal_id;
}
int max_function_literal_id() const { return max_function_literal_id_; }
void set_max_function_literal_id(int max_function_literal_id) {
max_function_literal_id_ = max_function_literal_id;
}
// Getters for individual compiler hints.
bool is_declaration() const;
bool requires_class_field_init() const;
@ -236,6 +241,7 @@ class V8_EXPORT_PRIVATE ParseInfo {
int start_position_;
int end_position_;
int function_literal_id_;
int max_function_literal_id_;
// TODO(titzer): Move handles and isolate out of ParseInfo.
Isolate* isolate_;

View File

@ -809,6 +809,8 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
}
}
info->set_max_function_literal_id(GetLastFunctionLiteralId());
// Make sure the target stack is empty.
DCHECK(target_stack_ == NULL);

View File

@ -204,8 +204,13 @@ RUNTIME_FUNCTION(Runtime_SetCode) {
target_shared->set_native(was_native);
target_shared->set_profiler_ticks(source_shared->profiler_ticks());
target_shared->set_function_literal_id(source_shared->function_literal_id());
SharedFunctionInfo::SetScript(
target_shared, Handle<Object>(source_shared->script(), isolate));
Handle<Object> source_script(source_shared->script(), isolate);
if (source_script->IsScript()) {
SharedFunctionInfo::SetScript(source_shared,
isolate->factory()->undefined_value());
}
SharedFunctionInfo::SetScript(target_shared, source_script);
// Set the code of the target function.
target->ReplaceCode(source_shared->code());

View File

@ -100,15 +100,31 @@ RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) {
}
}
// Recreate the shared function infos array after changing the IDs of all
// SharedFunctionInfos.
RUNTIME_FUNCTION(Runtime_LiveEditFixupScript) {
HandleScope scope(isolate);
CHECK(isolate->debug()->live_edit_enabled());
DCHECK_EQ(args.length(), 2);
CONVERT_ARG_CHECKED(JSValue, script_value, 0);
CONVERT_INT32_ARG_CHECKED(max_function_literal_id, 1);
CHECK(script_value->value()->IsScript());
Handle<Script> script(Script::cast(script_value->value()));
LiveEdit::FixupScript(script, max_function_literal_id);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) {
HandleScope scope(isolate);
CHECK(isolate->debug()->live_edit_enabled());
DCHECK(args.length() == 1);
DCHECK_EQ(args.length(), 2);
CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
CONVERT_INT32_ARG_CHECKED(new_function_literal_id, 1);
CHECK(SharedInfoWrapper::IsInstance(shared_info));
LiveEdit::FunctionSourceUpdated(shared_info);
LiveEdit::FunctionSourceUpdated(shared_info, new_function_literal_id);
return isolate->heap()->undefined_value();
}

View File

@ -346,13 +346,13 @@ namespace internal {
F(CreateArrayLiteral, 4, 1) \
F(CreateArrayLiteralStubBailout, 3, 1)
#define FOR_EACH_INTRINSIC_LIVEEDIT(F) \
F(LiveEditFindSharedFunctionInfosForScript, 1, 1) \
F(LiveEditGatherCompileInfo, 2, 1) \
F(LiveEditReplaceScript, 3, 1) \
F(LiveEditFunctionSourceUpdated, 1, 1) \
F(LiveEditFunctionSourceUpdated, 2, 1) \
F(LiveEditReplaceFunctionCode, 2, 1) \
F(LiveEditFixupScript, 2, 1) \
F(LiveEditFunctionSetScript, 2, 1) \
F(LiveEditReplaceRefToNestedFunction, 3, 1) \
F(LiveEditPatchFunctionPositions, 2, 1) \

View File

@ -6398,7 +6398,7 @@ TEST(SharedFunctionInfoIterator) {
}
{
SharedFunctionInfo::Iterator iterator(isolate);
SharedFunctionInfo::GlobalIterator iterator(isolate);
while (iterator.Next()) sfi_count--;
}

View File

@ -30,9 +30,9 @@ void GetTopLevelFunctionInfo(
Handle<JSFunction> toplevel_fn = v8::Utils::OpenHandle(*script);
Handle<Script> i_script =
handle(Script::cast(toplevel_fn->shared()->script()));
SharedFunctionInfo::ScriptIterator iterator(i_script);
WeakFixedArray::Iterator iter(i_script->shared_function_infos());
while (SharedFunctionInfo* shared = iter.Next<SharedFunctionInfo>()) {
while (SharedFunctionInfo* shared = iterator.Next()) {
std::unique_ptr<char[]> name = String::cast(shared->name())->ToCString();
is_compiled->insert(std::make_pair(name.get(), shared->is_compiled()));
}

View File

@ -1806,10 +1806,10 @@ TEST(CodeSerializerEagerCompilationAndPreAge) {
HandleScope i_scope(i_isolate);
Handle<SharedFunctionInfo> toplevel = v8::Utils::OpenHandle(*unbound);
Handle<Script> script(Script::cast(toplevel->script()));
WeakFixedArray::Iterator iterator(script->shared_function_infos());
// Every function has been pre-compiled from the code cache.
int count = 0;
while (SharedFunctionInfo* shared = iterator.Next<SharedFunctionInfo>()) {
SharedFunctionInfo::ScriptIterator iterator(script);
while (SharedFunctionInfo* shared = iterator.Next()) {
CHECK(shared->is_compiled());
CHECK_EQ(Code::kPreAgedCodeAge, shared->code()->GetAge());
count++;

View File

@ -91,13 +91,15 @@ Handle<SharedFunctionInfo> CreateSharedFunctionInfo(
source = isolate->factory()->NewStringFromAsciiChecked(test_script);
}
Handle<Script> script = isolate->factory()->NewScript(source);
Handle<FixedArray> infos = isolate->factory()->NewFixedArray(3);
script->set_shared_function_infos(*infos);
Handle<SharedFunctionInfo> shared = isolate->factory()->NewSharedFunctionInfo(
isolate->factory()->NewStringFromAsciiChecked("f"),
isolate->builtins()->CompileLazy(), false);
SharedFunctionInfo::SetScript(shared, script);
shared->set_end_position(source->length());
shared->set_outer_scope_info(ScopeInfo::Empty(isolate));
shared->set_function_literal_id(1);
SharedFunctionInfo::SetScript(shared, script);
return scope.CloseAndEscape(shared);
}