Commit 5dee5ade authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[sfi] Remove SFI function literal id field (reland^2)

SharedFunctionInfos store their original function literal's id. This is
also their index in the Script's SFI list.

The function literal id is only needed for lazy compilation and live edit,
and access only has to be fast in the former. So, we can move the SFI
function literal id field to UncompiledData, and if patching with live
edit, or discarding compiled code, we can perform a slower linear search
through the Script's SFI list.

This is a reland of
 1) https://chromium-review.googlesource.com/1082480 and
 2) https://chromium-review.googlesource.com/1128854
the differences being:
 1) caching the literal id on UncompiledData rather than always linearly
    searching the SFI list, and removing the unused runtime-liveedit.cc
    file instead of fixing it to support this change.
 2) clearing padding on UncompiledData now that it has 3 int32 fields,
    making its end unaligned on x64.

TBR=yangguo@chromium.org,marja@chromium.org,ulan@chromium.org,cbruni@chromium.org

Bug: chromium:818642
Change-Id: I58dcb12a2a60a680f662568da428e01189c62638
Reviewed-on: https://chromium-review.googlesource.com/1138325Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54473}
parent 414b841b
......@@ -623,10 +623,9 @@ Handle<JSFunction> Genesis::CreateEmptyFunction() {
Handle<WeakFixedArray> infos = factory()->NewWeakFixedArray(2);
script->set_shared_function_infos(*infos);
empty_function->shared()->set_scope_info(*scope_info);
empty_function->shared()->set_function_literal_id(1);
empty_function->shared()->DontAdaptArguments();
SharedFunctionInfo::SetScript(handle(empty_function->shared(), isolate()),
script);
script, 1);
return empty_function;
}
......
......@@ -121,7 +121,7 @@ void UnoptimizedCompileJob::PrepareOnMainThread(Isolate* isolate) {
unicode_cache_.reset(new UnicodeCache());
parse_info_->set_unicode_cache(unicode_cache_.get());
parse_info_->set_function_literal_id(shared_->function_literal_id());
parse_info_->set_function_literal_id(shared_->FunctionLiteralId(isolate));
if (V8_UNLIKELY(FLAG_runtime_stats)) {
parse_info_->set_runtime_call_stats(new (parse_info_->zone())
RuntimeCallStats());
......@@ -196,6 +196,7 @@ void UnoptimizedCompileJob::PrepareOnMainThread(Isolate* isolate) {
shared_->EndPosition() - offset));
parse_info_->set_character_stream(std::move(stream));
}
parser_.reset(new Parser(parse_info_.get()));
parser_->DeserializeScopeChain(isolate, parse_info_.get(),
parse_info_->maybe_outer_scope_info());
......
......@@ -779,12 +779,13 @@ class FunctionDataMap : public ThreadVisitor {
FunctionData{literal, should_restart});
}
bool Lookup(SharedFunctionInfo* sfi, FunctionData** data) {
if (!sfi->script()->IsScript() || sfi->function_literal_id() == -1) {
bool Lookup(Isolate* isolate, SharedFunctionInfo* sfi, FunctionData** data) {
int function_literal_id = sfi->FunctionLiteralId(isolate);
if (!sfi->script()->IsScript() || function_literal_id == -1) {
return false;
}
Script* script = Script::cast(sfi->script());
return Lookup(script->id(), sfi->function_literal_id(), data);
return Lookup(script->id(), function_literal_id, data);
}
bool Lookup(Handle<Script> script, FunctionLiteral* literal,
......@@ -799,20 +800,20 @@ class FunctionDataMap : public ThreadVisitor {
if (obj->IsSharedFunctionInfo()) {
SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
FunctionData* data = nullptr;
if (!Lookup(sfi, &data)) continue;
if (!Lookup(isolate, sfi, &data)) continue;
data->shared = handle(sfi, isolate);
} else if (obj->IsJSFunction()) {
JSFunction* js_function = JSFunction::cast(obj);
SharedFunctionInfo* sfi = js_function->shared();
FunctionData* data = nullptr;
if (!Lookup(sfi, &data)) continue;
if (!Lookup(isolate, sfi, &data)) continue;
data->js_functions.emplace_back(js_function, isolate);
} else if (obj->IsJSGeneratorObject()) {
JSGeneratorObject* gen = JSGeneratorObject::cast(obj);
if (gen->is_closed()) continue;
SharedFunctionInfo* sfi = gen->function()->shared();
FunctionData* data = nullptr;
if (!Lookup(sfi, &data)) continue;
if (!Lookup(isolate, sfi, &data)) continue;
data->running_generators.emplace_back(gen, isolate);
}
}
......@@ -842,7 +843,7 @@ class FunctionDataMap : public ThreadVisitor {
stack_position = FunctionData::BELOW_NON_DROPPABLE_FRAME;
}
FunctionData* data = nullptr;
if (!Lookup(*sfi, &data)) continue;
if (!Lookup(isolate, *sfi, &data)) continue;
if (!data->should_restart) continue;
data->stack_position = stack_position;
*restart_frame_fp = frame->fp();
......@@ -866,7 +867,7 @@ class FunctionDataMap : public ThreadVisitor {
it.frame()->GetFunctions(&sfis);
for (auto& sfi : sfis) {
FunctionData* data = nullptr;
if (!Lookup(*sfi, &data)) continue;
if (!Lookup(isolate, *sfi, &data)) continue;
data->stack_position = FunctionData::ARCHIVED_THREAD;
}
}
......@@ -931,7 +932,7 @@ bool CanRestartFrame(Isolate* isolate, Address fp,
JavaScriptFrame::cast(restart_frame)->GetFunctions(&sfis);
for (auto& sfi : sfis) {
FunctionData* data = nullptr;
if (!function_data_map.Lookup(*sfi, &data)) continue;
if (!function_data_map.Lookup(isolate, *sfi, &data)) continue;
auto new_literal_it = changed.find(data->literal);
if (new_literal_it == changed.end()) continue;
if (new_literal_it->second->scope()->new_target_var()) {
......@@ -1060,11 +1061,14 @@ void LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
new_script->shared_function_infos()->Get(
mapping.second->function_literal_id());
sfi->set_function_literal_id(mapping.second->function_literal_id());
sfi->set_script(*new_script);
if (sfi->HasUncompiledData()) {
sfi->uncompiled_data()->set_function_literal_id(
mapping.second->function_literal_id());
}
new_script->shared_function_infos()->Set(
mapping.second->function_literal_id(), HeapObjectReference::Weak(*sfi));
DCHECK_EQ(sfi->function_literal_id(),
DCHECK_EQ(sfi->FunctionLiteralId(isolate),
mapping.second->function_literal_id());
// Swap the now-redundant, newly compiled SFI into the old script, so that
......@@ -1076,12 +1080,16 @@ void LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
SharedFunctionInfo* redundant_new_sfi =
SharedFunctionInfo::cast(redundant_new_sfi_obj);
redundant_new_sfi->set_function_literal_id(
mapping.first->function_literal_id());
redundant_new_sfi->set_script(*script);
if (redundant_new_sfi->HasUncompiledData()) {
redundant_new_sfi->uncompiled_data()->set_function_literal_id(
mapping.first->function_literal_id());
}
script->shared_function_infos()->Set(
mapping.first->function_literal_id(),
HeapObjectReference::Weak(redundant_new_sfi));
DCHECK_EQ(redundant_new_sfi->FunctionLiteralId(isolate),
mapping.first->function_literal_id());
}
if (sfi->HasUncompiledDataWithPreParsedScope()) {
......@@ -1095,13 +1103,12 @@ void LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
}
if (!sfi->HasBytecodeArray()) continue;
Handle<BytecodeArray> bytecode(sfi->GetBytecodeArray(), isolate);
Handle<FixedArray> constants(bytecode->constant_pool(), isolate);
FixedArray* constants = sfi->GetBytecodeArray()->constant_pool();
for (int i = 0; i < constants->length(); ++i) {
if (!constants->get(i)->IsSharedFunctionInfo()) continue;
FunctionData* data = nullptr;
if (!function_data_map.Lookup(SharedFunctionInfo::cast(constants->get(i)),
&data)) {
if (!function_data_map.Lookup(
isolate, SharedFunctionInfo::cast(constants->get(i)), &data)) {
continue;
}
auto change_it = changed.find(data->literal);
......@@ -1153,7 +1160,7 @@ void LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
// inner_sfi, but the resulting FunctionData will still be referring to
// the old, unchanged SFI.
FunctionData* data = nullptr;
if (!function_data_map.Lookup(inner_sfi, &data)) continue;
if (!function_data_map.Lookup(isolate, inner_sfi, &data)) continue;
Handle<SharedFunctionInfo> old_unchanged_inner_sfi =
data->shared.ToHandleChecked();
// Now some sanity checks. Make sure that this inner_sfi is not the
......@@ -1164,17 +1171,21 @@ void LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
DCHECK_EQ(old_unchanged_inner_sfi->script(), *new_script);
// ... and that the id of the unchanged SFI matches the unchanged target
// literal's id.
DCHECK_EQ(old_unchanged_inner_sfi->function_literal_id(),
DCHECK_EQ(old_unchanged_inner_sfi->FunctionLiteralId(isolate),
unchanged[data->literal]->function_literal_id());
constants->set(i, *old_unchanged_inner_sfi);
}
}
#ifdef DEBUG
{
// Check that all the functions in the new script are valid.
// Check that all the functions in the new script are valid and that their
// function literals match what is expected.
DisallowHeapAllocation no_gc;
SharedFunctionInfo::ScriptIterator it(isolate, *new_script);
while (SharedFunctionInfo* sfi = it.Next()) {
DCHECK_EQ(sfi->script(), *new_script);
DCHECK_EQ(sfi->FunctionLiteralId(isolate), it.CurrentIndex());
if (!sfi->HasBytecodeArray()) continue;
// Check that all the functions in this function's constant pool are also
......@@ -1187,7 +1198,7 @@ void LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
SharedFunctionInfo::cast(constants->get(i));
DCHECK_EQ(inner_sfi->script(), *new_script);
DCHECK_EQ(inner_sfi, new_script->shared_function_infos()
->Get(inner_sfi->function_literal_id())
->Get(inner_sfi->FunctionLiteralId(isolate))
->GetHeapObject());
}
}
......
......@@ -2514,19 +2514,23 @@ Handle<PreParsedScopeData> Factory::NewPreParsedScopeData(int length) {
Handle<UncompiledDataWithoutPreParsedScope>
Factory::NewUncompiledDataWithoutPreParsedScope(int32_t start_position,
int32_t end_position) {
int32_t end_position,
int32_t function_literal_id) {
Handle<UncompiledDataWithoutPreParsedScope> result(
UncompiledDataWithoutPreParsedScope::cast(
New(uncompiled_data_without_pre_parsed_scope_map(), TENURED)),
isolate());
result->set_start_position(start_position);
result->set_end_position(end_position);
result->set_function_literal_id(function_literal_id);
result->clear_padding();
return result;
}
Handle<UncompiledDataWithPreParsedScope>
Factory::NewUncompiledDataWithPreParsedScope(
int32_t start_position, int32_t end_position,
int32_t start_position, int32_t end_position, int32_t function_literal_id,
Handle<PreParsedScopeData> pre_parsed_scope_data) {
Handle<UncompiledDataWithPreParsedScope> result(
UncompiledDataWithPreParsedScope::cast(
......@@ -2534,7 +2538,10 @@ Factory::NewUncompiledDataWithPreParsedScope(
isolate());
result->set_start_position(start_position);
result->set_end_position(end_position);
result->set_function_literal_id(function_literal_id);
result->set_pre_parsed_scope_data(*pre_parsed_scope_data);
result->clear_padding();
return result;
}
......@@ -3416,7 +3423,8 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForLiteral(
Handle<SharedFunctionInfo> shared = NewSharedFunctionInfoForBuiltin(
literal->name(), Builtins::kCompileLazy, kind);
SharedFunctionInfo::InitFromFunctionLiteral(shared, literal, is_toplevel);
SharedFunctionInfo::SetScript(shared, script, false);
SharedFunctionInfo::SetScript(shared, script, literal->function_literal_id(),
false);
return shared;
}
......@@ -3504,7 +3512,6 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
share->set_script(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_function_identifier_or_debug_info(*undefined_value(),
SKIP_WRITE_BARRIER);
share->set_function_literal_id(FunctionLiteral::kIdTypeInvalid);
#if V8_SFI_HAS_UNIQUE_ID
share->set_unique_id(isolate()->GetNextUniqueSharedFunctionInfoId());
#endif
......
......@@ -728,10 +728,12 @@ class V8_EXPORT_PRIVATE Factory {
Handle<UncompiledDataWithoutPreParsedScope>
NewUncompiledDataWithoutPreParsedScope(int32_t start_position,
int32_t end_position);
int32_t end_position,
int32_t function_literal_id);
Handle<UncompiledDataWithPreParsedScope> NewUncompiledDataWithPreParsedScope(
int32_t start_position, int32_t end_position, Handle<PreParsedScopeData>);
int32_t start_position, int32_t end_position, int32_t function_literal_id,
Handle<PreParsedScopeData>);
// Create an External object for V8's external API.
Handle<JSObject> NewExternal(void* value);
......
......@@ -12895,9 +12895,8 @@ void Map::SetPrototype(Isolate* isolate, Handle<Map> map,
map->set_prototype(*prototype, wb_mode);
}
Handle<Object> CacheInitialJSArrayMaps(
Handle<Context> native_context, Handle<Map> initial_map) {
Handle<Object> CacheInitialJSArrayMaps(Handle<Context> native_context,
Handle<Map> initial_map) {
// Replace all of the cached initial array maps in the native context with
// the appropriate transitioned elements kind maps.
Handle<Map> current_map = initial_map;
......@@ -13018,7 +13017,6 @@ void JSFunction::SetPrototype(Handle<JSFunction> function,
SetInstancePrototype(isolate, function, construct_prototype);
}
void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
Handle<Object> prototype) {
if (map->prototype() != *prototype)
......@@ -13736,8 +13734,8 @@ SharedFunctionInfo* SharedFunctionInfo::GlobalIterator::Next() {
void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
Handle<Object> script_object,
int function_literal_id,
bool reset_preparsed_scope_data) {
DCHECK_NE(shared->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
if (shared->script() == *script_object) return;
Isolate* isolate = shared->GetIsolate();
......@@ -13755,15 +13753,14 @@ void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
Handle<WeakFixedArray> list =
handle(script->shared_function_infos(), isolate);
#ifdef DEBUG
DCHECK_LT(shared->function_literal_id(), list->length());
MaybeObject* maybe_object = list->Get(shared->function_literal_id());
DCHECK_LT(function_literal_id, list->length());
MaybeObject* maybe_object = list->Get(function_literal_id);
HeapObject* heap_object;
if (maybe_object->ToWeakHeapObject(&heap_object)) {
DCHECK_EQ(heap_object, *shared);
}
#endif
list->Set(shared->function_literal_id(),
HeapObjectReference::Weak(*shared));
list->Set(function_literal_id, HeapObjectReference::Weak(*shared));
} else {
Handle<Object> list = isolate->factory()->noscript_shared_function_infos();
......@@ -13789,15 +13786,14 @@ void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> 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<WeakFixedArray> infos(old_script->shared_function_infos(), isolate);
if (shared->function_literal_id() < infos->length()) {
MaybeObject* raw = old_script->shared_function_infos()->Get(
shared->function_literal_id());
if (function_literal_id < infos->length()) {
MaybeObject* raw =
old_script->shared_function_infos()->Get(function_literal_id);
HeapObject* heap_object;
if (raw->ToWeakHeapObject(&heap_object) && heap_object == *shared) {
old_script->shared_function_infos()->Set(
shared->function_literal_id(),
HeapObjectReference::Strong(
ReadOnlyRoots(isolate).undefined_value()));
function_literal_id, HeapObjectReference::Strong(
ReadOnlyRoots(isolate).undefined_value()));
}
}
} else {
......@@ -13910,6 +13906,27 @@ bool SharedFunctionInfo::IsInlineable() {
int SharedFunctionInfo::SourceSize() { return EndPosition() - StartPosition(); }
int SharedFunctionInfo::FindIndexInScript(Isolate* isolate) const {
DisallowHeapAllocation no_gc;
Object* script_obj = script();
if (!script_obj->IsScript()) return FunctionLiteral::kIdTypeInvalid;
WeakFixedArray* shared_info_list =
Script::cast(script_obj)->shared_function_infos();
SharedFunctionInfo::ScriptIterator iterator(
isolate, Handle<WeakFixedArray>(&shared_info_list));
for (SharedFunctionInfo* shared = iterator.Next(); shared != nullptr;
shared = iterator.Next()) {
if (shared == this) {
return iterator.CurrentIndex();
}
}
return FunctionLiteral::kIdTypeInvalid;
}
void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
bool has_prototype_slot,
int requested_embedder_fields,
......@@ -14052,7 +14069,6 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
// FunctionKind must have already been set.
DCHECK(lit->kind() == shared_info->kind());
shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
shared_info->set_function_literal_id(lit->function_literal_id());
DCHECK_IMPLIES(lit->requires_instance_fields_initializer(),
IsClassConstructor(lit->kind()));
shared_info->set_requires_instance_fields_initializer(
......@@ -14099,7 +14115,7 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
Handle<UncompiledData> data =
isolate->factory()->NewUncompiledDataWithPreParsedScope(
lit->start_position(), lit->end_position(),
pre_parsed_scope_data);
lit->function_literal_id(), pre_parsed_scope_data);
shared_info->set_uncompiled_data(*data);
needs_position_info = false;
}
......@@ -14109,7 +14125,8 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
if (needs_position_info) {
Handle<UncompiledData> data =
isolate->factory()->NewUncompiledDataWithoutPreParsedScope(
lit->start_position(), lit->end_position());
lit->start_position(), lit->end_position(),
lit->function_literal_id());
shared_info->set_uncompiled_data(*data);
}
}
......
......@@ -55,6 +55,16 @@ void PreParsedScopeData::clear_padding() {
CAST_ACCESSOR(UncompiledData)
INT32_ACCESSORS(UncompiledData, start_position, kStartPositionOffset)
INT32_ACCESSORS(UncompiledData, end_position, kEndPositionOffset)
INT32_ACCESSORS(UncompiledData, function_literal_id, kFunctionLiteralIdOffset)
void UncompiledData::clear_padding() {
// For archs where kIntSize < kPointerSize, there will be padding at the end
// of the data.
if (kUnalignedSize < kSize) {
memset(reinterpret_cast<void*>(address() + kUnalignedSize), 0,
kSize - kUnalignedSize);
}
}
CAST_ACCESSOR(UncompiledDataWithoutPreParsedScope)
......@@ -77,7 +87,6 @@ ACCESSORS(SharedFunctionInfo, script, Object, kScriptOffset)
ACCESSORS(SharedFunctionInfo, function_identifier_or_debug_info, Object,
kFunctionIdentifierOrDebugInfoOffset)
INT_ACCESSORS(SharedFunctionInfo, function_literal_id, kFunctionLiteralIdOffset)
#if V8_SFI_HAS_UNIQUE_ID
INT_ACCESSORS(SharedFunctionInfo, unique_id, kUniqueIdOffset)
#endif
......@@ -650,6 +659,21 @@ WasmExportedFunctionData* SharedFunctionInfo::wasm_exported_function_data()
return WasmExportedFunctionData::cast(function_data());
}
int SharedFunctionInfo::FunctionLiteralId(Isolate* isolate) const {
// Fast path for the common case when the SFI is uncompiled and so the
// function literal id is already in the uncompiled data.
if (HasUncompiledData()) {
int id = uncompiled_data()->function_literal_id();
// Make sure the id is what we should have found with the slow path.
DCHECK_EQ(id, FindIndexInScript(isolate));
return id;
}
// Otherwise, search for the function in the SFI's script's function list,
// and return its index in that list.
return FindIndexInScript(isolate);
}
bool SharedFunctionInfo::HasDebugInfo() const {
return function_identifier_or_debug_info()->IsDebugInfo();
}
......@@ -737,8 +761,11 @@ void SharedFunctionInfo::DiscardCompiled(
int start_position = shared_info->StartPosition();
int end_position = shared_info->EndPosition();
int function_literal_id = shared_info->FunctionLiteralId(isolate);
if (shared_info->is_compiled()) {
DisallowHeapAllocation no_gc;
HeapObject* outer_scope_info;
if (shared_info->scope_info()->HasOuterScopeInfo()) {
outer_scope_info = shared_info->scope_info()->OuterScopeInfo();
......@@ -764,7 +791,7 @@ void SharedFunctionInfo::DiscardCompiled(
// validity checks, since we're performing the unusual task of decompiling.
Handle<UncompiledData> data =
isolate->factory()->NewUncompiledDataWithoutPreParsedScope(
start_position, end_position);
start_position, end_position, function_literal_id);
shared_info->set_function_data(*data);
}
}
......
......@@ -70,13 +70,15 @@ class UncompiledData : public HeapObject {
public:
DECL_INT32_ACCESSORS(start_position)
DECL_INT32_ACCESSORS(end_position)
DECL_INT32_ACCESSORS(function_literal_id)
DECL_CAST(UncompiledData)
#define UNCOMPILED_DATA_FIELDS(V) \
V(kStartPositionOffset, kInt32Size) \
V(kEndPositionOffset, kInt32Size) \
/* Total size. */ \
#define UNCOMPILED_DATA_FIELDS(V) \
V(kStartPositionOffset, kInt32Size) \
V(kEndPositionOffset, kInt32Size) \
V(kFunctionLiteralIdOffset, kInt32Size) \
/* Total size. */ \
V(kUnalignedSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, UNCOMPILED_DATA_FIELDS)
......@@ -84,6 +86,9 @@ class UncompiledData : public HeapObject {
static const int kSize = POINTER_SIZE_ALIGN(kUnalignedSize);
// Clear uninitialized padding space.
inline void clear_padding();
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(UncompiledData);
};
......@@ -118,16 +123,17 @@ class UncompiledDataWithPreParsedScope : public UncompiledData {
V(kPreParsedScopeDataOffset, kPointerSize) \
V(kEndOfPointerFieldsOffset, 0) \
/* Total size. */ \
V(kUnalignedSize, 0)
V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(UncompiledData::kSize,
UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_FIELDS)
#undef UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_FIELDS
static const int kSize = POINTER_SIZE_ALIGN(kUnalignedSize);
// Make sure the size is aligned
STATIC_ASSERT(kSize == POINTER_SIZE_ALIGN(kSize));
typedef FixedBodyDescriptor<kStartOfPointerFieldsOffset,
kEndOfPointerFieldsOffset, kUnalignedSize>
kEndOfPointerFieldsOffset, kSize>
BodyDescriptor;
// No weak fields.
typedef BodyDescriptor BodyDescriptorWeak;
......@@ -185,7 +191,7 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
// function info is added to the list on the script.
V8_EXPORT_PRIVATE static void SetScript(
Handle<SharedFunctionInfo> shared, Handle<Object> script_object,
bool reset_preparsed_scope_data = true);
int function_literal_id, bool reset_preparsed_scope_data = true);
// Layout description of the optimized code map.
static const int kEntriesStart = 0;
......@@ -255,11 +261,6 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
// function. The value is only reliable when the function has been compiled.
DECL_UINT16_ACCESSORS(expected_nof_properties)
// [function_literal_id] - uniquely identifies the FunctionLiteral this
// SharedFunctionInfo represents within its script, or -1 if this
// SharedFunctionInfo object doesn't correspond to a parsed FunctionLiteral.
DECL_INT_ACCESSORS(function_literal_id)
#if V8_SFI_HAS_UNIQUE_ID
// [unique_id] - For --trace-maps purposes, an identifier that's persistent
// even if the GC moves this SharedFunctionInfo.
......@@ -341,6 +342,9 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
inline String* inferred_name();
inline void set_inferred_name(String* inferred_name);
// Get the function literal id associated with this function, for parsing.
inline int FunctionLiteralId(Isolate* isolate) const;
// The function is subject to debugging if a debug info is attached.
inline bool HasDebugInfo() const;
inline DebugInfo* GetDebugInfo() const;
......@@ -530,6 +534,7 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
ScriptIterator(Isolate* isolate,
Handle<WeakFixedArray> shared_function_infos);
SharedFunctionInfo* Next();
int CurrentIndex() const { return index_ - 1; }
// Reset the iterator to run on |script|.
void Reset(Script* script);
......@@ -582,7 +587,6 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
V(kFunctionIdentifierOrDebugInfoOffset, kPointerSize) \
V(kEndOfPointerFieldsOffset, 0) \
/* Raw data fields. */ \
V(kFunctionLiteralIdOffset, kInt32Size) \
V(kUniqueIdOffset, kUniqueIdFieldSize) \
V(kLengthOffset, kUInt16Size) \
V(kFormalParameterCountOffset, kUInt16Size) \
......@@ -662,6 +666,10 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
inline uint16_t length() const;
// Find the index of this function in the parent script. Slow path of
// FunctionLiteralId.
int FindIndexInScript(Isolate* isolate) const;
DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
};
......
......@@ -68,7 +68,7 @@ ParseInfo::ParseInfo(Isolate* isolate, Handle<SharedFunctionInfo> shared)
set_function_flags(shared->flags());
set_start_position(shared->StartPosition());
set_end_position(shared->EndPosition());
function_literal_id_ = shared->function_literal_id();
function_literal_id_ = shared->FunctionLiteralId(isolate);
set_language_mode(shared->language_mode());
set_asm_wasm_broken(shared->is_asm_wasm_broken());
......
......@@ -114,16 +114,17 @@ RUNTIME_FUNCTION(Runtime_SetCode) {
bool was_native = target_shared->native();
target_shared->set_flags(source_shared->flags());
target_shared->set_native(was_native);
target_shared->set_function_literal_id(source_shared->function_literal_id());
target_shared->set_scope_info(source_shared->scope_info());
Handle<Object> source_script(source_shared->script(), isolate);
int function_literal_id = source_shared->FunctionLiteralId(isolate);
if (source_script->IsScript()) {
SharedFunctionInfo::SetScript(source_shared,
isolate->factory()->undefined_value());
isolate->factory()->undefined_value(),
function_literal_id);
}
SharedFunctionInfo::SetScript(target_shared, source_script);
SharedFunctionInfo::SetScript(target_shared, source_script,
function_literal_id);
// Set the code of the target function.
target->set_code(source_shared->GetCode());
......
// Copyright 2014 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/runtime/runtime-utils.h"
#include "src/arguments.h"
#include "src/debug/debug.h"
#include "src/debug/debug-frames.h"
#include "src/debug/liveedit.h"
#include "src/frames-inl.h"
#include "src/isolate-inl.h"
#include "src/runtime/runtime.h"
namespace v8 {
namespace internal {
// For a script finds all SharedFunctionInfo's in the heap that points
// to this script. Returns JSArray of SharedFunctionInfo wrapped
// in OpaqueReferences.
RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(JSValue, script_value, 0);
CHECK(script_value->value()->IsScript());
Handle<Script> script(Script::cast(script_value->value()), isolate);
std::vector<Handle<SharedFunctionInfo>> found;
Heap* heap = isolate->heap();
{
HeapIterator iterator(heap);
HeapObject* heap_obj;
while ((heap_obj = iterator.next()) != nullptr) {
if (!heap_obj->IsSharedFunctionInfo()) continue;
SharedFunctionInfo* shared = SharedFunctionInfo::cast(heap_obj);
if (shared->script() != *script) continue;
found.push_back(Handle<SharedFunctionInfo>(shared, isolate));
}
}
int found_size = static_cast<int>(found.size());
Handle<FixedArray> result = isolate->factory()->NewFixedArray(found_size);
for (int i = 0; i < found_size; ++i) {
Handle<SharedFunctionInfo> shared = found[i];
SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create(isolate);
Handle<String> name(shared->Name(), isolate);
info_wrapper.SetProperties(name, shared->StartPosition(),
shared->EndPosition(), shared);
result->set(i, *info_wrapper.GetJSArray());
}
return *isolate->factory()->NewJSArrayWithElements(result);
}
// For a script calculates compilation information about all its functions.
// The script source is explicitly specified by the second argument.
// The source of the actual script is not used, however it is important that
// all generated code keeps references to this particular instance of script.
// Returns a JSArray of compilation infos. The array is ordered so that
// each function with all its descendant is always stored in a continues range
// with the function itself going first. The root function is a script function.
RUNTIME_FUNCTION(Runtime_LiveEditGatherCompileInfo) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_CHECKED(JSValue, script, 0);
CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
CHECK(script->value()->IsScript());
Handle<Script> script_handle(Script::cast(script->value()), isolate);
RETURN_RESULT_OR_FAILURE(
isolate, LiveEdit::GatherCompileInfo(isolate, script_handle, source));
}
// Changes the source of the script to a new_source.
// If old_script_name is provided (i.e. is a String), also creates a copy of
// the script with its original source and sends notification to debugger.
RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, old_script_name, 2);
CHECK(original_script_value->value()->IsScript());
Handle<Script> original_script(Script::cast(original_script_value->value()),
isolate);
Handle<Object> old_script = LiveEdit::ChangeScriptSource(
isolate, original_script, new_source, old_script_name);
if (old_script->IsScript()) {
Handle<Script> script_handle = Handle<Script>::cast(old_script);
return *Script::GetWrapper(script_handle);
} else {
return ReadOnlyRoots(isolate).null_value();
}
}
// Recreate the shared function infos array after changing the IDs of all
// SharedFunctionInfos.
RUNTIME_FUNCTION(Runtime_LiveEditFixupScript) {
HandleScope scope(isolate);
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()), isolate);
LiveEdit::FixupScript(isolate, script, max_function_literal_id);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) {
HandleScope scope(isolate);
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, new_function_literal_id);
return ReadOnlyRoots(isolate).undefined_value();
}
// Replaces code of SharedFunctionInfo with a new one.
RUNTIME_FUNCTION(Runtime_LiveEditReplaceFunctionCode) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
CHECK(SharedInfoWrapper::IsInstance(shared_info));
LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
return ReadOnlyRoots(isolate).undefined_value();
}
// Connects SharedFunctionInfo to another script.
RUNTIME_FUNCTION(Runtime_LiveEditFunctionSetScript) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, script_object, 1);
if (function_object->IsJSValue()) {
Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
if (script_object->IsJSValue()) {
CHECK(JSValue::cast(*script_object)->value()->IsScript());
Script* script = Script::cast(JSValue::cast(*script_object)->value());
script_object = Handle<Object>(script, isolate);
}
CHECK(function_wrapper->value()->IsSharedFunctionInfo());
LiveEdit::SetFunctionScript(function_wrapper, script_object);
} else {
// Just ignore this. We may not have a SharedFunctionInfo for some functions
// and we check it in this function.
}
return ReadOnlyRoots(isolate).undefined_value();
}
// In a code of a parent function replaces original function as embedded object
// with a substitution one.
RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
CHECK(parent_wrapper->value()->IsSharedFunctionInfo());
CHECK(orig_wrapper->value()->IsSharedFunctionInfo());
CHECK(subst_wrapper->value()->IsSharedFunctionInfo());
LiveEdit::ReplaceRefToNestedFunction(isolate->heap(), parent_wrapper,
orig_wrapper, subst_wrapper);
return ReadOnlyRoots(isolate).undefined_value();
}
// Updates positions of a shared function info (first parameter) according
// to script source change. Text change is described in second parameter as
// array of groups of 3 numbers:
// (change_begin, change_end, change_end_new_position).
// Each group describes a change in text; groups are sorted by change_begin.
RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
CHECK(SharedInfoWrapper::IsInstance(shared_array));
LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
return ReadOnlyRoots(isolate).undefined_value();
}
// For array of SharedFunctionInfo's (each wrapped in JSValue)
// checks that none of them have activations on stacks (of any thread).
// Returns array of the same length with corresponding results of
// LiveEdit::FunctionPatchabilityStatus type.
RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSArray, old_shared_array, 0);
CONVERT_ARG_HANDLE_CHECKED(JSArray, new_shared_array, 1);
CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 2);
USE(new_shared_array);
CHECK(old_shared_array->length()->IsSmi());
CHECK(new_shared_array->length() == old_shared_array->length());
CHECK(old_shared_array->HasFastElements());
CHECK(new_shared_array->HasFastElements());
int array_length = Smi::ToInt(old_shared_array->length());
for (int i = 0; i < array_length; i++) {
Handle<Object> old_element;
Handle<Object> new_element;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, old_element,
JSReceiver::GetElement(isolate, old_shared_array, i));
CHECK(old_element->IsJSValue() &&
Handle<JSValue>::cast(old_element)->value()->IsSharedFunctionInfo());
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, new_element,
JSReceiver::GetElement(isolate, new_shared_array, i));
CHECK(
new_element->IsUndefined(isolate) ||
(new_element->IsJSValue() &&
Handle<JSValue>::cast(new_element)->value()->IsSharedFunctionInfo()));
}
return *LiveEdit::CheckAndDropActivations(old_shared_array, new_shared_array,
do_drop);
}
// Compares 2 strings line-by-line, then token-wise and returns diff in form
// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
// of diff chunks.
RUNTIME_FUNCTION(Runtime_LiveEditCompareStrings) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
Handle<JSArray> result = LiveEdit::CompareStrings(isolate, s1, s2);
uint32_t array_length = 0;
CHECK(result->length()->ToArrayLength(&array_length));
if (array_length > 0) {
isolate->debug()->feature_tracker()->Track(DebugFeatureTracker::kLiveEdit);
}
return *result;
}
} // namespace internal
} // namespace v8
......@@ -38,15 +38,15 @@ Handle<SharedFunctionInfo> CreateSharedFunctionInfo(
isolate->factory()->NewSharedFunctionInfoForBuiltin(
isolate->factory()->NewStringFromAsciiChecked("f"),
Builtins::kCompileLazy);
int function_literal_id = 1;
// Ensure that the function can be compiled lazily.
shared->set_uncompiled_data(
*isolate->factory()->NewUncompiledDataWithoutPreParsedScope(
0, source->length()));
0, source->length(), function_literal_id));
// Make sure we have an outer scope info, even though it's empty
shared->set_raw_outer_scope_info_or_feedback_metadata(
ScopeInfo::Empty(isolate));
shared->set_function_literal_id(1);
SharedFunctionInfo::SetScript(shared, script);
SharedFunctionInfo::SetScript(shared, script, function_literal_id);
return scope.CloseAndEscape(shared);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment