Added v8::Module::GetModuleRequestPosition method

This method returns position of importing stmt in module source.

R=neis@chromium.org

Bug: chromium:721589
Change-Id: I8639796a001fdfec7cf5aa1bf1a27493f7a757a9
Reviewed-on: https://chromium-review.googlesource.com/541322
Reviewed-by: Georg Neis <neis@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Commit-Queue: Aleksey Kozyatinskiy <kozyatinskiy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46105}
This commit is contained in:
Alexey Kozyatinskiy 2017-06-21 13:30:56 +01:00 committed by Commit Bot
parent 95d18f7b31
commit d9be9fd88d
14 changed files with 164 additions and 65 deletions

View File

@ -1075,6 +1075,22 @@ class V8_EXPORT UnboundScript {
static const int kNoScriptId = 0;
};
/**
* A location in JavaScript source.
*/
class V8_EXPORT Location {
public:
int GetLineNumber() { return line_number_; }
int GetColumnNumber() { return column_number_; }
Location(int line_number, int column_number)
: line_number_(line_number), column_number_(column_number) {}
private:
int line_number_;
int column_number_;
};
/**
* This is an unfinished experimental feature, and is only exposed
* here for internal testing purposes. DO NOT USE.
@ -1094,6 +1110,12 @@ class V8_EXPORT Module {
*/
Local<String> GetModuleRequest(int i) const;
/**
* Returns the source location (line number and column number) of the ith
* module specifier's first occurrence in this module.
*/
Location GetModuleRequestLocation(int i) const;
/**
* Returns the identity hash for this object.
*/

View File

@ -2130,6 +2130,21 @@ Local<String> Module::GetModuleRequest(int i) const {
return ToApiHandle<String>(i::handle(module_requests->get(i), isolate));
}
Location Module::GetModuleRequestLocation(int i) const {
CHECK_GE(i, 0);
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
i::HandleScope scope(isolate);
i::Handle<i::Module> self = Utils::OpenHandle(this);
i::Handle<i::FixedArray> module_request_positions(
self->info()->module_request_positions(), isolate);
CHECK_LT(i, module_request_positions->length());
int position = i::Smi::cast(module_request_positions->get(i))->value();
i::Handle<i::Script> script(self->script(), isolate);
i::Script::PositionInfo info;
i::Script::GetPositionInfo(script, position, &info, i::Script::WITH_OFFSET);
return v8::Location(info.line, info.column);
}
int Module::GetIdentityHash() const { return Utils::OpenHandle(this)->hash(); }
bool Module::Instantiate(Local<Context> context,

View File

@ -12,28 +12,33 @@
namespace v8 {
namespace internal {
void ModuleDescriptor::AddImport(
const AstRawString* import_name, const AstRawString* local_name,
const AstRawString* module_request, Scanner::Location loc, Zone* zone) {
void ModuleDescriptor::AddImport(const AstRawString* import_name,
const AstRawString* local_name,
const AstRawString* module_request,
const Scanner::Location loc,
const Scanner::Location specifier_loc,
Zone* zone) {
Entry* entry = new (zone) Entry(loc);
entry->local_name = local_name;
entry->import_name = import_name;
entry->module_request = AddModuleRequest(module_request);
entry->module_request = AddModuleRequest(module_request, specifier_loc);
AddRegularImport(entry);
}
void ModuleDescriptor::AddStarImport(
const AstRawString* local_name, const AstRawString* module_request,
Scanner::Location loc, Zone* zone) {
void ModuleDescriptor::AddStarImport(const AstRawString* local_name,
const AstRawString* module_request,
const Scanner::Location loc,
const Scanner::Location specifier_loc,
Zone* zone) {
Entry* entry = new (zone) Entry(loc);
entry->local_name = local_name;
entry->module_request = AddModuleRequest(module_request);
entry->module_request = AddModuleRequest(module_request, specifier_loc);
AddNamespaceImport(entry, zone);
}
void ModuleDescriptor::AddEmptyImport(const AstRawString* module_request) {
AddModuleRequest(module_request);
void ModuleDescriptor::AddEmptyImport(const AstRawString* module_request,
const Scanner::Location specifier_loc) {
AddModuleRequest(module_request, specifier_loc);
}
@ -46,24 +51,27 @@ void ModuleDescriptor::AddExport(
AddRegularExport(entry);
}
void ModuleDescriptor::AddExport(
const AstRawString* import_name, const AstRawString* export_name,
const AstRawString* module_request, Scanner::Location loc, Zone* zone) {
void ModuleDescriptor::AddExport(const AstRawString* import_name,
const AstRawString* export_name,
const AstRawString* module_request,
const Scanner::Location loc,
const Scanner::Location specifier_loc,
Zone* zone) {
DCHECK_NOT_NULL(import_name);
DCHECK_NOT_NULL(export_name);
Entry* entry = new (zone) Entry(loc);
entry->export_name = export_name;
entry->import_name = import_name;
entry->module_request = AddModuleRequest(module_request);
entry->module_request = AddModuleRequest(module_request, specifier_loc);
AddSpecialExport(entry, zone);
}
void ModuleDescriptor::AddStarExport(
const AstRawString* module_request, Scanner::Location loc, Zone* zone) {
void ModuleDescriptor::AddStarExport(const AstRawString* module_request,
const Scanner::Location loc,
const Scanner::Location specifier_loc,
Zone* zone) {
Entry* entry = new (zone) Entry(loc);
entry->module_request = AddModuleRequest(module_request);
entry->module_request = AddModuleRequest(module_request, specifier_loc);
AddSpecialExport(entry, zone);
}

View File

@ -32,20 +32,23 @@ class ModuleDescriptor : public ZoneObject {
// import x from "foo.js";
// import {x} from "foo.js";
// import {x as y} from "foo.js";
void AddImport(
const AstRawString* import_name, const AstRawString* local_name,
const AstRawString* module_request, const Scanner::Location loc,
Zone* zone);
void AddImport(const AstRawString* import_name,
const AstRawString* local_name,
const AstRawString* module_request,
const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone);
// import * as x from "foo.js";
void AddStarImport(
const AstRawString* local_name, const AstRawString* module_request,
const Scanner::Location loc, Zone* zone);
void AddStarImport(const AstRawString* local_name,
const AstRawString* module_request,
const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone);
// import "foo.js";
// import {} from "foo.js";
// export {} from "foo.js"; (sic!)
void AddEmptyImport(const AstRawString* module_request);
void AddEmptyImport(const AstRawString* module_request,
const Scanner::Location specifier_loc);
// export {x};
// export {x as y};
@ -58,15 +61,16 @@ class ModuleDescriptor : public ZoneObject {
// export {x} from "foo.js";
// export {x as y} from "foo.js";
void AddExport(
const AstRawString* export_name, const AstRawString* import_name,
const AstRawString* module_request, const Scanner::Location loc,
Zone* zone);
void AddExport(const AstRawString* export_name,
const AstRawString* import_name,
const AstRawString* module_request,
const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone);
// export * from "foo.js";
void AddStarExport(
const AstRawString* module_request, const Scanner::Location loc,
Zone* zone);
void AddStarExport(const AstRawString* module_request,
const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone);
// Check if module is well-formed and report error if not.
// Also canonicalize indirect exports.
@ -114,8 +118,14 @@ class ModuleDescriptor : public ZoneObject {
enum CellIndexKind { kInvalid, kExport, kImport };
static CellIndexKind GetCellIndexKind(int cell_index);
struct ModuleRequest {
int index;
int position;
ModuleRequest(int index, int position) : index(index), position(position) {}
};
// Module requests.
const ZoneMap<const AstRawString*, int>& module_requests() const {
const ZoneMap<const AstRawString*, ModuleRequest>& module_requests() const {
return module_requests_;
}
@ -179,7 +189,7 @@ class ModuleDescriptor : public ZoneObject {
private:
// TODO(neis): Use STL datastructure instead of ZoneList?
ZoneMap<const AstRawString*, int> module_requests_;
ZoneMap<const AstRawString*, ModuleRequest> module_requests_;
ZoneList<const Entry*> special_exports_;
ZoneList<const Entry*> namespace_imports_;
ZoneMultimap<const AstRawString*, Entry*> regular_exports_;
@ -212,13 +222,16 @@ class ModuleDescriptor : public ZoneObject {
// Assign a cell_index of 0 to anything else.
void AssignCellIndices();
int AddModuleRequest(const AstRawString* specifier) {
int AddModuleRequest(const AstRawString* specifier,
Scanner::Location specifier_loc) {
DCHECK_NOT_NULL(specifier);
int module_requests_count = static_cast<int>(module_requests_.size());
auto it = module_requests_
.insert(std::make_pair(specifier, module_requests_count))
.insert(std::make_pair(specifier,
ModuleRequest(module_requests_count,
specifier_loc.beg_pos)))
.first;
return it->second;
return it->second.index;
}
};

View File

@ -2013,6 +2013,7 @@ Handle<Module> Factory::NewModule(Handle<SharedFunctionInfo> code) {
module->set_hash(isolate()->GenerateIdentityHash(Smi::kMaxValue));
module->set_module_namespace(isolate()->heap()->undefined_value());
module->set_requested_modules(*requested_modules);
module->set_script(Script::cast(code->script()));
module->set_status(Module::kUnprepared);
DCHECK(!module->instantiated());
DCHECK(!module->evaluated());

View File

@ -1249,6 +1249,7 @@ void Module::ModuleVerify() {
VerifyPointer(exports());
VerifyPointer(module_namespace());
VerifyPointer(requested_modules());
VerifyPointer(script());
VerifySmiField(kHashOffset);
VerifySmiField(kStatusOffset);

View File

@ -4629,6 +4629,7 @@ ACCESSORS(Module, regular_exports, FixedArray, kRegularExportsOffset)
ACCESSORS(Module, regular_imports, FixedArray, kRegularImportsOffset)
ACCESSORS(Module, module_namespace, HeapObject, kModuleNamespaceOffset)
ACCESSORS(Module, requested_modules, FixedArray, kRequestedModulesOffset)
ACCESSORS(Module, script, Script, kScriptOffset)
SMI_ACCESSORS(Module, status, kStatusOffset)
SMI_ACCESSORS(Module, hash, kHashOffset)

View File

@ -1307,6 +1307,7 @@ void Module::ModulePrint(std::ostream& os) { // NOLINT
os << "\n - code: " << Brief(code());
os << "\n - exports: " << Brief(exports());
os << "\n - requested_modules: " << Brief(requested_modules());
os << "\n - script: " << Brief(script());
os << "\n - instantiated, evaluated: " << instantiated() << ", "
<< evaluated();
os << "\n";

View File

@ -4868,6 +4868,9 @@ class Module : public Struct {
// ModuleInfo::module_requests.
DECL_ACCESSORS(requested_modules, FixedArray)
// [script]: Script from which the module originates.
DECL_ACCESSORS(script, Script)
// Get the ModuleInfo associated with the code.
inline ModuleInfo* info() const;
@ -4908,7 +4911,8 @@ class Module : public Struct {
static const int kRequestedModulesOffset =
kModuleNamespaceOffset + kPointerSize;
static const int kStatusOffset = kRequestedModulesOffset + kPointerSize;
static const int kSize = kStatusOffset + kPointerSize;
static const int kScriptOffset = kStatusOffset + kPointerSize;
static const int kSize = kScriptOffset + kPointerSize;
private:
static void CreateExport(Handle<Module> module, int cell_index,

View File

@ -49,6 +49,10 @@ class ModuleInfo : public FixedArray {
return FixedArray::cast(get(kNamespaceImportsIndex));
}
inline FixedArray* module_request_positions() const {
return FixedArray::cast(get(kModuleRequestPositionsIndex));
}
// Accessors for [regular_exports].
int RegularExportCount() const;
String* RegularExportLocalName(int i) const;
@ -63,7 +67,9 @@ class ModuleInfo : public FixedArray {
return regular_exports() == other->regular_exports() &&
regular_imports() == other->regular_imports() &&
special_exports() == other->special_exports() &&
namespace_imports() == other->namespace_imports();
namespace_imports() == other->namespace_imports() &&
module_requests() == other->module_requests() &&
module_request_positions() == other->module_request_positions();
}
#endif
@ -76,6 +82,7 @@ class ModuleInfo : public FixedArray {
kRegularExportsIndex,
kNamespaceImportsIndex,
kRegularImportsIndex,
kModuleRequestPositionsIndex,
kLength
};
enum {

View File

@ -853,10 +853,14 @@ Handle<ModuleInfoEntry> ModuleInfoEntry::New(Isolate* isolate,
Handle<ModuleInfo> ModuleInfo::New(Isolate* isolate, Zone* zone,
ModuleDescriptor* descr) {
// Serialize module requests.
Handle<FixedArray> module_requests = isolate->factory()->NewFixedArray(
static_cast<int>(descr->module_requests().size()));
int size = static_cast<int>(descr->module_requests().size());
Handle<FixedArray> module_requests = isolate->factory()->NewFixedArray(size);
Handle<FixedArray> module_request_positions =
isolate->factory()->NewFixedArray(size);
for (const auto& elem : descr->module_requests()) {
module_requests->set(elem.second, *elem.first->string());
module_requests->set(elem.second.index, *elem.first->string());
module_request_positions->set(elem.second.index,
Smi::FromInt(elem.second.position));
}
// Serialize special exports.
@ -903,6 +907,7 @@ Handle<ModuleInfo> ModuleInfo::New(Isolate* isolate, Zone* zone,
result->set(kRegularExportsIndex, *regular_exports);
result->set(kNamespaceImportsIndex, *namespace_imports);
result->set(kRegularImportsIndex, *regular_imports);
result->set(kModuleRequestPositionsIndex, *module_request_positions);
return result;
}

View File

@ -1148,9 +1148,10 @@ void Parser::ParseImportDeclaration(bool* ok) {
// 'import' ModuleSpecifier ';'
if (tok == Token::STRING) {
Scanner::Location specifier_loc = scanner()->peek_location();
const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK_VOID);
ExpectSemicolon(CHECK_OK_VOID);
module()->AddEmptyImport(module_specifier);
module()->AddEmptyImport(module_specifier, specifier_loc);
return;
}
@ -1194,6 +1195,7 @@ void Parser::ParseImportDeclaration(bool* ok) {
}
ExpectContextualKeyword(Token::FROM, CHECK_OK_VOID);
Scanner::Location specifier_loc = scanner()->peek_location();
const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK_VOID);
ExpectSemicolon(CHECK_OK_VOID);
@ -1207,23 +1209,25 @@ void Parser::ParseImportDeclaration(bool* ok) {
if (module_namespace_binding != nullptr) {
module()->AddStarImport(module_namespace_binding, module_specifier,
module_namespace_binding_loc, zone());
module_namespace_binding_loc, specifier_loc,
zone());
}
if (import_default_binding != nullptr) {
module()->AddImport(ast_value_factory()->default_string(),
import_default_binding, module_specifier,
import_default_binding_loc, zone());
import_default_binding_loc, specifier_loc, zone());
}
if (named_imports != nullptr) {
if (named_imports->length() == 0) {
module()->AddEmptyImport(module_specifier);
module()->AddEmptyImport(module_specifier, specifier_loc);
} else {
for (int i = 0; i < named_imports->length(); ++i) {
const NamedImport* import = named_imports->at(i);
module()->AddImport(import->import_name, import->local_name,
module_specifier, import->location, zone());
module_specifier, import->location, specifier_loc,
zone());
}
}
}
@ -1317,9 +1321,10 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
Consume(Token::MUL);
loc = scanner()->location();
ExpectContextualKeyword(Token::FROM, CHECK_OK);
Scanner::Location specifier_loc = scanner()->peek_location();
const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
ExpectSemicolon(CHECK_OK);
module()->AddStarExport(module_specifier, loc, zone());
module()->AddStarExport(module_specifier, loc, specifier_loc, zone());
return factory()->NewEmptyStatement(pos);
}
@ -1342,7 +1347,9 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
ParseExportClause(&export_names, &export_locations, &original_names,
&reserved_loc, CHECK_OK);
const AstRawString* module_specifier = nullptr;
Scanner::Location specifier_loc;
if (CheckContextualKeyword(Token::FROM)) {
specifier_loc = scanner()->peek_location();
module_specifier = ParseModuleSpecifier(CHECK_OK);
} else if (reserved_loc.IsValid()) {
// No FromClause, so reserved words are invalid in ExportClause.
@ -1360,11 +1367,12 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
export_locations[i], zone());
}
} else if (length == 0) {
module()->AddEmptyImport(module_specifier);
module()->AddEmptyImport(module_specifier, specifier_loc);
} else {
for (int i = 0; i < length; ++i) {
module()->AddExport(original_names[i], export_names[i],
module_specifier, export_locations[i], zone());
module_specifier, export_locations[i],
specifier_loc, zone());
}
}
return factory()->NewEmptyStatement(pos);

View File

@ -58,14 +58,21 @@ TEST(ModuleInstantiationFailures) {
Local<String> source_text = v8_str(
"import './foo.js';"
"export {} from './bar.js';");
"\nexport {} from './bar.js';");
ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate());
ScriptCompiler::Source source(source_text, origin);
Local<Module> module =
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
CHECK_EQ(2, module->GetModuleRequestsLength());
CHECK(v8_str("./foo.js")->StrictEquals(module->GetModuleRequest(0)));
v8::Location loc = module->GetModuleRequestLocation(0);
CHECK_EQ(0, loc.GetLineNumber());
CHECK_EQ(7, loc.GetColumnNumber());
CHECK(v8_str("./bar.js")->StrictEquals(module->GetModuleRequest(1)));
loc = module->GetModuleRequestLocation(1);
CHECK_EQ(1, loc.GetLineNumber());
CHECK_EQ(15, loc.GetColumnNumber());
// Instantiation should fail.
{

View File

@ -6799,18 +6799,24 @@ TEST(ModuleParsingInternals) {
CHECK_EQ(5u, descriptor->module_requests().size());
for (const auto& elem : descriptor->module_requests()) {
if (elem.first->IsOneByteEqualTo("m.js"))
CHECK_EQ(0, elem.second);
else if (elem.first->IsOneByteEqualTo("n.js"))
CHECK_EQ(1, elem.second);
else if (elem.first->IsOneByteEqualTo("p.js"))
CHECK_EQ(2, elem.second);
else if (elem.first->IsOneByteEqualTo("q.js"))
CHECK_EQ(3, elem.second);
else if (elem.first->IsOneByteEqualTo("bar.js"))
CHECK_EQ(4, elem.second);
else
if (elem.first->IsOneByteEqualTo("m.js")) {
CHECK_EQ(0, elem.second.index);
CHECK_EQ(51, elem.second.position);
} else if (elem.first->IsOneByteEqualTo("n.js")) {
CHECK_EQ(1, elem.second.index);
CHECK_EQ(72, elem.second.position);
} else if (elem.first->IsOneByteEqualTo("p.js")) {
CHECK_EQ(2, elem.second.index);
CHECK_EQ(123, elem.second.position);
} else if (elem.first->IsOneByteEqualTo("q.js")) {
CHECK_EQ(3, elem.second.index);
CHECK_EQ(249, elem.second.position);
} else if (elem.first->IsOneByteEqualTo("bar.js")) {
CHECK_EQ(4, elem.second.index);
CHECK_EQ(370, elem.second.position);
} else {
CHECK(false);
}
}
CHECK_EQ(3, descriptor->special_exports().length());