bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
switch (variable->location()) {
case Variable::UNALLOCATED:
- globals_.Add(variable->name());
- globals_.Add(variable->binding_needs_init()
- ? isolate()->factory()->the_hole_value()
- : isolate()->factory()->undefined_value());
+ globals_->Add(variable->name());
+ globals_->Add(variable->binding_needs_init()
+ ? isolate()->factory()->the_hole_value()
+ : isolate()->factory()->undefined_value());
break;
case Variable::PARAMETER:
Variable* variable = proxy->var();
switch (variable->location()) {
case Variable::UNALLOCATED: {
- globals_.Add(variable->name());
+ globals_->Add(variable->name());
Handle<SharedFunctionInfo> function =
Compiler::BuildFunctionInfo(declaration->fun(), script());
// Check for stack-overflow exception.
if (function.is_null()) return SetStackOverflow();
- globals_.Add(function);
+ globals_->Add(function);
break;
}
void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
+ Handle<JSModule> instance = declaration->module()->interface()->Instance();
+ ASSERT(!instance.is_null());
+
switch (variable->location()) {
- case Variable::UNALLOCATED:
- // TODO(rossberg): initialize module instance object
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "[ ModuleDeclaration");
+ globals_->Add(variable->name());
+ globals_->Add(instance);
+ Visit(declaration->module());
break;
+ }
case Variable::CONTEXT: {
Comment cmnt(masm_, "[ ModuleDeclaration");
EmitDebugCheckDeclarationContext(variable);
- // TODO(rossberg): initialize module instance object
+ __ mov(r1, Operand(instance));
+ __ str(r1, ContextOperand(cp, variable->index()));
+ Visit(declaration->module());
break;
}
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
Scope* declaration_scope = scope()->DeclarationScope();
- if (declaration_scope->is_global_scope()) {
+ if (declaration_scope->is_global_scope() ||
+ declaration_scope->is_module_scope()) {
// Contexts nested in the global context have a canonical empty function
// as their closure, not the anonymous closure containing the global
// code. Pass a smi sentinel and let the runtime look up the empty
}
-#define INCREASE_NODE_COUNT(NodeType) \
+#define REGULAR_NODE(NodeType) \
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
increase_node_count(); \
}
+#define DONT_OPTIMIZE_NODE(NodeType) \
+ void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
+ increase_node_count(); \
+ add_flag(kDontOptimize); \
+ add_flag(kDontInline); \
+ add_flag(kDontSelfOptimize); \
+ }
+#define DONT_INLINE_NODE(NodeType) \
+ void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
+ increase_node_count(); \
+ add_flag(kDontInline); \
+ }
+#define DONT_SELFOPTIMIZE_NODE(NodeType) \
+ void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
+ increase_node_count(); \
+ add_flag(kDontSelfOptimize); \
+ }
-INCREASE_NODE_COUNT(VariableDeclaration)
-INCREASE_NODE_COUNT(FunctionDeclaration)
-INCREASE_NODE_COUNT(ModuleDeclaration)
-INCREASE_NODE_COUNT(ImportDeclaration)
-INCREASE_NODE_COUNT(ExportDeclaration)
-INCREASE_NODE_COUNT(ModuleLiteral)
-INCREASE_NODE_COUNT(ModuleVariable)
-INCREASE_NODE_COUNT(ModulePath)
-INCREASE_NODE_COUNT(ModuleUrl)
-INCREASE_NODE_COUNT(Block)
-INCREASE_NODE_COUNT(ExpressionStatement)
-INCREASE_NODE_COUNT(EmptyStatement)
-INCREASE_NODE_COUNT(IfStatement)
-INCREASE_NODE_COUNT(ContinueStatement)
-INCREASE_NODE_COUNT(BreakStatement)
-INCREASE_NODE_COUNT(ReturnStatement)
-INCREASE_NODE_COUNT(Conditional)
-INCREASE_NODE_COUNT(Literal)
-INCREASE_NODE_COUNT(ObjectLiteral)
-INCREASE_NODE_COUNT(Assignment)
-INCREASE_NODE_COUNT(Throw)
-INCREASE_NODE_COUNT(Property)
-INCREASE_NODE_COUNT(UnaryOperation)
-INCREASE_NODE_COUNT(CountOperation)
-INCREASE_NODE_COUNT(BinaryOperation)
-INCREASE_NODE_COUNT(CompareOperation)
-INCREASE_NODE_COUNT(ThisFunction)
-INCREASE_NODE_COUNT(Call)
-INCREASE_NODE_COUNT(CallNew)
-
-#undef INCREASE_NODE_COUNT
-
-
-void AstConstructionVisitor::VisitWithStatement(WithStatement* node) {
- increase_node_count();
- add_flag(kDontOptimize);
- add_flag(kDontInline);
-}
-
-
-void AstConstructionVisitor::VisitSwitchStatement(SwitchStatement* node) {
- increase_node_count();
- add_flag(kDontInline);
-}
-
-
-void AstConstructionVisitor::VisitDoWhileStatement(DoWhileStatement* node) {
- increase_node_count();
- add_flag(kDontSelfOptimize);
-}
-
-
-void AstConstructionVisitor::VisitWhileStatement(WhileStatement* node) {
- increase_node_count();
- add_flag(kDontSelfOptimize);
-}
-
-
-void AstConstructionVisitor::VisitForStatement(ForStatement* node) {
- increase_node_count();
- add_flag(kDontSelfOptimize);
-}
-
-
-void AstConstructionVisitor::VisitForInStatement(ForInStatement* node) {
- increase_node_count();
- add_flag(kDontSelfOptimize);
-}
-
-
-void AstConstructionVisitor::VisitTryCatchStatement(TryCatchStatement* node) {
- increase_node_count();
- add_flag(kDontOptimize);
- add_flag(kDontInline);
-}
-
-
-void AstConstructionVisitor::VisitTryFinallyStatement(
- TryFinallyStatement* node) {
- increase_node_count();
- add_flag(kDontOptimize);
- add_flag(kDontInline);
-}
-
-
-void AstConstructionVisitor::VisitDebuggerStatement(DebuggerStatement* node) {
- increase_node_count();
- add_flag(kDontOptimize);
- add_flag(kDontInline);
-}
-
-
-void AstConstructionVisitor::VisitFunctionLiteral(FunctionLiteral* node) {
- increase_node_count();
- add_flag(kDontInline);
-}
-
-
-void AstConstructionVisitor::VisitSharedFunctionInfoLiteral(
- SharedFunctionInfoLiteral* node) {
- increase_node_count();
- add_flag(kDontOptimize);
- add_flag(kDontInline);
-}
-
-
-void AstConstructionVisitor::VisitVariableProxy(VariableProxy* node) {
- increase_node_count();
- // In theory, we'd have to add:
- // if(node->var()->IsLookupSlot()) { add_flag(kDontInline); }
- // However, node->var() is usually not bound yet at VariableProxy creation
- // time, and LOOKUP variables only result from constructs that cannot
- // be inlined anyway.
-}
-
-
-void AstConstructionVisitor::VisitRegExpLiteral(RegExpLiteral* node) {
- increase_node_count();
- add_flag(kDontInline); // TODO(1322): Allow materialized literals.
-}
-
-
-void AstConstructionVisitor::VisitArrayLiteral(ArrayLiteral* node) {
- increase_node_count();
- add_flag(kDontInline); // TODO(1322): Allow materialized literals.
-}
-
+REGULAR_NODE(VariableDeclaration)
+REGULAR_NODE(FunctionDeclaration)
+REGULAR_NODE(Block)
+REGULAR_NODE(ExpressionStatement)
+REGULAR_NODE(EmptyStatement)
+REGULAR_NODE(IfStatement)
+REGULAR_NODE(ContinueStatement)
+REGULAR_NODE(BreakStatement)
+REGULAR_NODE(ReturnStatement)
+REGULAR_NODE(Conditional)
+REGULAR_NODE(Literal)
+REGULAR_NODE(ObjectLiteral)
+REGULAR_NODE(Assignment)
+REGULAR_NODE(Throw)
+REGULAR_NODE(Property)
+REGULAR_NODE(UnaryOperation)
+REGULAR_NODE(CountOperation)
+REGULAR_NODE(BinaryOperation)
+REGULAR_NODE(CompareOperation)
+REGULAR_NODE(ThisFunction)
+REGULAR_NODE(Call)
+REGULAR_NODE(CallNew)
+// In theory, for VariableProxy we'd have to add:
+// if (node->var()->IsLookupSlot()) add_flag(kDontInline);
+// But node->var() is usually not bound yet at VariableProxy creation time, and
+// LOOKUP variables only result from constructs that cannot be inlined anyway.
+REGULAR_NODE(VariableProxy)
+
+DONT_OPTIMIZE_NODE(ModuleDeclaration)
+DONT_OPTIMIZE_NODE(ImportDeclaration)
+DONT_OPTIMIZE_NODE(ExportDeclaration)
+DONT_OPTIMIZE_NODE(ModuleLiteral)
+DONT_OPTIMIZE_NODE(ModuleVariable)
+DONT_OPTIMIZE_NODE(ModulePath)
+DONT_OPTIMIZE_NODE(ModuleUrl)
+DONT_OPTIMIZE_NODE(WithStatement)
+DONT_OPTIMIZE_NODE(TryCatchStatement)
+DONT_OPTIMIZE_NODE(TryFinallyStatement)
+DONT_OPTIMIZE_NODE(DebuggerStatement)
+DONT_OPTIMIZE_NODE(SharedFunctionInfoLiteral)
+
+DONT_INLINE_NODE(SwitchStatement)
+DONT_INLINE_NODE(FunctionLiteral)
+DONT_INLINE_NODE(RegExpLiteral) // TODO(1322): Allow materialized literals.
+DONT_INLINE_NODE(ArrayLiteral) // TODO(1322): Allow materialized literals.
+
+DONT_SELFOPTIMIZE_NODE(DoWhileStatement)
+DONT_SELFOPTIMIZE_NODE(WhileStatement)
+DONT_SELFOPTIMIZE_NODE(ForStatement)
+DONT_SELFOPTIMIZE_NODE(ForInStatement)
void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
increase_node_count();
}
}
+#undef REGULAR_NODE
+#undef DONT_OPTIMIZE_NODE
+#undef DONT_INLINE_NODE
+#undef DONT_SELFOPTIMIZE_NODE
+
Handle<String> Literal::ToString() {
if (handle_->IsString()) return Handle<String>::cast(handle_);
ZoneList<Statement*>* statements() { return &statements_; }
bool is_initializer_block() const { return is_initializer_block_; }
- Scope* block_scope() const { return block_scope_; }
- void set_block_scope(Scope* block_scope) { block_scope_ = block_scope; }
+ Scope* scope() const { return scope_; }
+ void set_scope(Scope* scope) { scope_ = scope; }
protected:
template<class> friend class AstNodeFactory;
: BreakableStatement(isolate, labels, TARGET_FOR_NAMED_ONLY),
statements_(capacity),
is_initializer_block_(is_initializer_block),
- block_scope_(NULL) {
+ scope_(NULL) {
}
private:
ZoneList<Statement*> statements_;
bool is_initializer_block_;
- Scope* block_scope_;
+ Scope* scope_;
};
DECLARE_NODE_TYPE(ModuleLiteral)
Block* body() const { return body_; }
+ Handle<Context> context() const { return context_; }
protected:
template<class> friend class AstNodeFactory;
private:
Block* body_;
+ Handle<Context> context_;
};
}
+Handle<Context> Factory::NewModuleContext(Handle<Context> previous,
+ Handle<ScopeInfo> scope_info) {
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateModuleContext(*previous, *scope_info),
+ Context);
+}
+
+
Handle<Context> Factory::NewFunctionContext(int length,
Handle<JSFunction> function) {
CALL_HEAP_FUNCTION(
}
-Handle<Context> Factory::NewBlockContext(
- Handle<JSFunction> function,
- Handle<Context> previous,
- Handle<ScopeInfo> scope_info) {
+Handle<Context> Factory::NewBlockContext(Handle<JSFunction> function,
+ Handle<Context> previous,
+ Handle<ScopeInfo> scope_info) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateBlockContext(*function,
}
+Handle<JSModule> Factory::NewJSModule() {
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateJSModule(), JSModule);
+}
+
+
Handle<GlobalObject> Factory::NewGlobalObject(
Handle<JSFunction> constructor) {
CALL_HEAP_FUNCTION(isolate(),
// Create a global (but otherwise uninitialized) context.
Handle<Context> NewGlobalContext();
+ // Create a module context.
+ Handle<Context> NewModuleContext(Handle<Context> previous,
+ Handle<ScopeInfo> scope_info);
+
// Create a function context.
- Handle<Context> NewFunctionContext(int length,
- Handle<JSFunction> function);
+ Handle<Context> NewFunctionContext(int length, Handle<JSFunction> function);
// Create a catch context.
Handle<Context> NewCatchContext(Handle<JSFunction> function,
Handle<Context> previous,
Handle<JSObject> extension);
- // Create a 'block' context.
+ // Create a block context.
Handle<Context> NewBlockContext(Handle<JSFunction> function,
Handle<Context> previous,
Handle<ScopeInfo> scope_info);
// runtime.
Handle<JSObject> NewJSObjectFromMap(Handle<Map> map);
+ // JS modules are pretenured.
+ Handle<JSModule> NewJSModule();
+
// JS arrays are pretenured when allocated by the parser.
Handle<JSArray> NewJSArray(int capacity,
ElementsKind elements_kind = FAST_ELEMENTS,
void FullCodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
- ASSERT(globals_.is_empty());
+ ZoneList<Handle<Object> >* saved_globals = globals_;
+ ZoneList<Handle<Object> > inner_globals(10);
+ globals_ = &inner_globals;
+
AstVisitor::VisitDeclarations(declarations);
- if (!globals_.is_empty()) {
+ if (!globals_->is_empty()) {
// Invoke the platform-dependent code generator to do the actual
// declaration the global functions and variables.
Handle<FixedArray> array =
- isolate()->factory()->NewFixedArray(globals_.length(), TENURED);
- for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i));
+ isolate()->factory()->NewFixedArray(globals_->length(), TENURED);
+ for (int i = 0; i < globals_->length(); ++i)
+ array->set(i, *globals_->at(i));
DeclareGlobals(array);
- globals_.Clear();
}
+
+ globals_ = saved_globals;
}
void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) {
- // TODO(rossberg)
+ Handle<JSModule> instance = module->interface()->Instance();
+ ASSERT(!instance.is_null());
+
+ // Allocate a module context statically.
+ Block* block = module->body();
+ Scope* saved_scope = scope();
+ scope_ = block->scope();
+ Handle<ScopeInfo> scope_info = scope_->GetScopeInfo();
+
+ // Generate code for module creation and linking.
+ Comment cmnt(masm_, "[ ModuleLiteral");
+ SetStatementPosition(block);
+
+ if (scope_info->HasContext()) {
+ // Set up module context.
+ __ Push(scope_info);
+ __ Push(instance);
+ __ CallRuntime(Runtime::kPushModuleContext, 2);
+ StoreToFrameField(
+ StandardFrameConstants::kContextOffset, context_register());
+ }
+
+ {
+ Comment cmnt(masm_, "[ Declarations");
+ VisitDeclarations(scope_->declarations());
+ }
+
+ scope_ = saved_scope;
+ if (scope_info->HasContext()) {
+ // Pop module context.
+ LoadContextField(context_register(), Context::PREVIOUS_INDEX);
+ // Update local stack frame context field.
+ StoreToFrameField(
+ StandardFrameConstants::kContextOffset, context_register());
+ }
+
+ // Populate module instance object.
+ const PropertyAttributes attr =
+ static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE | DONT_ENUM);
+ for (Interface::Iterator it = module->interface()->iterator();
+ !it.done(); it.Advance()) {
+ if (it.interface()->IsModule()) {
+ Handle<Object> value = it.interface()->Instance();
+ ASSERT(!value.is_null());
+ JSReceiver::SetProperty(instance, it.name(), value, attr, kStrictMode);
+ } else {
+ // TODO(rossberg): set proper getters instead of undefined...
+ // instance->DefineAccessor(*it.name(), ACCESSOR_GETTER, *getter, attr);
+ Handle<Object> value(isolate()->heap()->undefined_value());
+ JSReceiver::SetProperty(instance, it.name(), value, attr, kStrictMode);
+ }
+ }
+ USE(instance->PreventExtensions());
}
void FullCodeGenerator::VisitModuleVariable(ModuleVariable* module) {
- // TODO(rossberg)
+ // Noting to do.
+ // The instance object is resolved statically through the module's interface.
}
void FullCodeGenerator::VisitModulePath(ModulePath* module) {
- // TODO(rossberg)
+ // Noting to do.
+ // The instance object is resolved statically through the module's interface.
}
Scope* saved_scope = scope();
// Push a block context when entering a block with block scoped variables.
- if (stmt->block_scope() != NULL) {
+ if (stmt->scope() != NULL) {
{ Comment cmnt(masm_, "[ Extend block context");
- scope_ = stmt->block_scope();
+ scope_ = stmt->scope();
Handle<ScopeInfo> scope_info = scope_->GetScopeInfo();
int heap_slots = scope_info->ContextLength() - Context::MIN_CONTEXT_SLOTS;
__ Push(scope_info);
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
// Pop block context if necessary.
- if (stmt->block_scope() != NULL) {
+ if (stmt->scope() != NULL) {
LoadContextField(context_register(), Context::PREVIOUS_INDEX);
// Update local stack frame context field.
StoreToFrameField(StandardFrameConstants::kContextOffset,
scope_(info->scope()),
nesting_stack_(NULL),
loop_depth_(0),
- globals_(10),
+ globals_(NULL),
context_(NULL),
bailout_entries_(info->HasDeoptimizationSupport()
? info->function()->ast_node_count() : 0),
virtual ~NestedBlock() {}
virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
- if (statement()->AsBlock()->block_scope() != NULL) {
+ if (statement()->AsBlock()->scope() != NULL) {
++(*context_length);
}
return previous_;
Label return_label_;
NestedStatement* nesting_stack_;
int loop_depth_;
- ZoneList<Handle<Object> > globals_;
+ ZoneList<Handle<Object> >* globals_;
const ExpressionContext* context_;
ZoneList<BailoutEntry> bailout_entries_;
ZoneList<BailoutEntry> stack_checks_;
}
+MaybeObject* Heap::AllocateJSModule() {
+ // Allocate a fresh map. Modules do not have a prototype.
+ Map* map;
+ MaybeObject* maybe_map = AllocateMap(JS_MODULE_TYPE, JSModule::kSize);
+ if (!maybe_map->To(&map)) return maybe_map;
+ // Allocate the object based on the map.
+ return AllocateJSObjectFromMap(map, TENURED);
+}
+
+
MaybeObject* Heap::AllocateJSArrayAndStorage(
ElementsKind elements_kind,
int length,
}
+MaybeObject* Heap::AllocateModuleContext(Context* previous,
+ ScopeInfo* scope_info) {
+ Object* result;
+ { MaybeObject* maybe_result =
+ AllocateFixedArrayWithHoles(scope_info->ContextLength(), TENURED);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ Context* context = reinterpret_cast<Context*>(result);
+ context->set_map_no_write_barrier(module_context_map());
+ context->set_previous(previous);
+ context->set_extension(scope_info);
+ context->set_global(previous->global());
+ return context;
+}
+
+
MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
Object* result;
MUST_USE_RESULT MaybeObject* AllocateJSObject(
JSFunction* constructor, PretenureFlag pretenure = NOT_TENURED);
+ MUST_USE_RESULT MaybeObject* AllocateJSModule();
+
// Allocate a JSArray with no elements
MUST_USE_RESULT MaybeObject* AllocateEmptyJSArray(
ElementsKind elements_kind,
// Allocate a global (but otherwise uninitialized) context.
MUST_USE_RESULT MaybeObject* AllocateGlobalContext();
+ // Allocate a module context.
+ MUST_USE_RESULT MaybeObject* AllocateModuleContext(Context* previous,
+ ScopeInfo* scope_info);
+
// Allocate a function context.
MUST_USE_RESULT MaybeObject* AllocateFunctionContext(int length,
JSFunction* function);
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- if (stmt->block_scope() != NULL) {
+ if (stmt->scope() != NULL) {
return Bailout("ScopedBlock");
}
BreakAndContinueInfo break_info(stmt);
void HGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* declaration) {
- VariableProxy* proxy = declaration->proxy();
- Variable* var = proxy->var();
- switch (var->location()) {
- case Variable::UNALLOCATED: {
- // TODO(rossberg)
- return;
- }
- case Variable::CONTEXT: {
- // TODO(rossberg)
- break;
- }
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::LOOKUP:
- UNREACHABLE();
- }
+ UNREACHABLE();
}
void HGraphBuilder::VisitImportDeclaration(ImportDeclaration* declaration) {
- VariableProxy* proxy = declaration->proxy();
- Variable* var = proxy->var();
- switch (var->location()) {
- case Variable::UNALLOCATED: {
- // TODO(rossberg)
- return;
- }
- case Variable::CONTEXT: {
- // TODO(rossberg)
- break;
- }
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::LOOKUP:
- UNREACHABLE();
- }
+ UNREACHABLE();
}
void HGraphBuilder::VisitExportDeclaration(ExportDeclaration* declaration) {
- // TODO(rossberg)
+ UNREACHABLE();
}
void HGraphBuilder::VisitModuleLiteral(ModuleLiteral* module) {
- // TODO(rossberg)
+ UNREACHABLE();
}
void HGraphBuilder::VisitModuleVariable(ModuleVariable* module) {
- // TODO(rossberg)
+ UNREACHABLE();
}
void HGraphBuilder::VisitModulePath(ModulePath* module) {
- // TODO(rossberg)
+ UNREACHABLE();
}
void HGraphBuilder::VisitModuleUrl(ModuleUrl* module) {
- // TODO(rossberg)
+ UNREACHABLE();
}
bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
switch (variable->location()) {
case Variable::UNALLOCATED:
- globals_.Add(variable->name());
- globals_.Add(variable->binding_needs_init()
- ? isolate()->factory()->the_hole_value()
- : isolate()->factory()->undefined_value());
+ globals_->Add(variable->name());
+ globals_->Add(variable->binding_needs_init()
+ ? isolate()->factory()->the_hole_value()
+ : isolate()->factory()->undefined_value());
break;
case Variable::PARAMETER:
Variable* variable = proxy->var();
switch (variable->location()) {
case Variable::UNALLOCATED: {
- globals_.Add(variable->name());
+ globals_->Add(variable->name());
Handle<SharedFunctionInfo> function =
Compiler::BuildFunctionInfo(declaration->fun(), script());
// Check for stack-overflow exception.
if (function.is_null()) return SetStackOverflow();
- globals_.Add(function);
+ globals_->Add(function);
break;
}
void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
+ Handle<JSModule> instance = declaration->module()->interface()->Instance();
+ ASSERT(!instance.is_null());
+
switch (variable->location()) {
- case Variable::UNALLOCATED:
- // TODO(rossberg): initialize module instance object
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "[ ModuleDeclaration");
+ globals_->Add(variable->name());
+ globals_->Add(instance);
+ Visit(declaration->module());
break;
+ }
case Variable::CONTEXT: {
Comment cmnt(masm_, "[ ModuleDeclaration");
EmitDebugCheckDeclarationContext(variable);
- // TODO(rossberg): initialize module instance object
+ __ mov(ContextOperand(esi, variable->index()), Immediate(instance));
+ Visit(declaration->module());
break;
}
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
Scope* declaration_scope = scope()->DeclarationScope();
- if (declaration_scope->is_global_scope()) {
+ if (declaration_scope->is_global_scope() ||
+ declaration_scope->is_module_scope()) {
// Contexts nested in the global context have a canonical empty function
// as their closure, not the anonymous closure containing the global
// code. Pass a smi sentinel and let the runtime look up the empty
PrintF("%*sthis = ", Nesting::current(), "");
this->Print(Nesting::current());
PrintF("%*s%s : ", Nesting::current(), "",
- (*reinterpret_cast<String**>(name))->ToAsciiArray());
+ (*static_cast<String**>(name))->ToAsciiArray());
interface->Print(Nesting::current());
}
#endif
#ifdef DEBUG
Nesting nested;
#endif
- reinterpret_cast<Interface*>(p->value)->Unify(interface, ok);
+ static_cast<Interface*>(p->value)->Unify(interface, ok);
}
#ifdef DEBUG
return;
}
+ // Merge instance.
+ if (!that->instance_.is_null()) {
+ if (!this->instance_.is_null() && *this->instance_ != *that->instance_) {
+ *ok = false;
+ return;
+ }
+ this->instance_ = that->instance_;
+ }
+
// Merge interfaces.
this->flags_ |= that->flags_;
that->forward_ = this;
if (*ok) Chase()->flags_ |= MODULE;
}
+ // Set associated instance object.
+ void MakeSingleton(Handle<JSModule> instance, bool* ok) {
+ *ok = IsModule() && Chase()->instance_.is_null();
+ if (*ok) Chase()->instance_ = instance;
+ }
+
// Do not allow any further refinements, directly or through unification.
void Freeze(bool* ok) {
*ok = IsValue() || IsModule();
// ---------------------------------------------------------------------------
// Accessors.
- // Look up an exported name. Returns NULL if not (yet) defined.
- Interface* Lookup(Handle<String> name);
-
// Check whether this is still a fully undetermined type.
bool IsUnknown() { return Chase()->flags_ == NONE; }
// Check whether this is closed (i.e. fully determined).
bool IsFrozen() { return Chase()->flags_ & FROZEN; }
+ Handle<JSModule> Instance() { return Chase()->instance_; }
+
+ // Look up an exported name. Returns NULL if not (yet) defined.
+ Interface* Lookup(Handle<String> name);
+
+ // ---------------------------------------------------------------------------
+ // Iterators.
+
+ // Use like:
+ // for (auto it = interface->iterator(); !it.done(); it.Advance()) {
+ // ... it.name() ... it.interface() ...
+ // }
+ class Iterator {
+ public:
+ bool done() const { return entry_ == NULL; }
+ Handle<String> name() const {
+ ASSERT(!done());
+ return Handle<String>(*static_cast<String**>(entry_->key));
+ }
+ Interface* interface() const {
+ ASSERT(!done());
+ return static_cast<Interface*>(entry_->value);
+ }
+ void Advance() { entry_ = exports_->Next(entry_); }
+
+ private:
+ friend class Interface;
+ explicit Iterator(const ZoneHashMap* exports)
+ : exports_(exports), entry_(exports ? exports->Start() : NULL) {}
+
+ const ZoneHashMap* exports_;
+ ZoneHashMap::Entry* entry_;
+ };
+
+ Iterator iterator() const { return Iterator(this->exports_); }
+
// ---------------------------------------------------------------------------
// Debugging.
#ifdef DEBUG
int flags_;
Interface* forward_; // Unification link
ZoneHashMap* exports_; // Module exports and their types (allocated lazily)
+ Handle<JSModule> instance_;
explicit Interface(int flags)
: flags_(flags),
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
JSObject::cast(this)->JSObjectVerify();
break;
+ case JS_MODULE_TYPE:
+ JSModule::cast(this)->JSModuleVerify();
+ break;
case JS_VALUE_TYPE:
JSValue::cast(this)->JSValueVerify();
break;
}
+void JSModule::JSModuleVerify() {
+ Object* v = context();
+ if (v->IsHeapObject()) {
+ VerifyHeapPointer(v);
+ }
+ CHECK(v->IsUndefined() || v->IsModuleContext());
+}
+
+
void JSValue::JSValueVerify() {
Object* v = value();
if (v->IsHeapObject()) {
map == heap->catch_context_map() ||
map == heap->with_context_map() ||
map == heap->global_context_map() ||
- map == heap->block_context_map());
+ map == heap->block_context_map() ||
+ map == heap->module_context_map());
}
return false;
}
}
+bool Object::IsModuleContext() {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map() ==
+ HeapObject::cast(this)->GetHeap()->module_context_map();
+}
+
+
bool Object::IsScopeInfo() {
return Object::IsHeapObject() &&
HeapObject::cast(this)->map() ==
TYPE_CHECKER(Oddball, ODDBALL_TYPE)
TYPE_CHECKER(JSGlobalPropertyCell, JS_GLOBAL_PROPERTY_CELL_TYPE)
TYPE_CHECKER(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE)
+TYPE_CHECKER(JSModule, JS_MODULE_TYPE)
TYPE_CHECKER(JSValue, JS_VALUE_TYPE)
TYPE_CHECKER(JSDate, JS_DATE_TYPE)
TYPE_CHECKER(JSMessageObject, JS_MESSAGE_OBJECT_TYPE)
// field operations considerably on average.
if (type == JS_OBJECT_TYPE) return JSObject::kHeaderSize;
switch (type) {
+ case JS_MODULE_TYPE:
+ return JSModule::kSize;
case JS_GLOBAL_PROXY_TYPE:
return JSGlobalProxy::kSize;
case JS_GLOBAL_OBJECT_TYPE:
}
+ACCESSORS(JSModule, context, Object, kContextOffset)
+
+
+JSModule* JSModule::cast(Object* obj) {
+ ASSERT(obj->IsJSModule());
+ ASSERT(HeapObject::cast(obj)->Size() == JSModule::kSize);
+ return reinterpret_cast<JSModule*>(obj);
+}
+
+
ACCESSORS(JSValue, value, Object, kValueOffset)
case ODDBALL_TYPE:
Oddball::cast(this)->to_string()->Print(out);
break;
+ case JS_MODULE_TYPE:
+ JSModule::cast(this)->JSModulePrint(out);
+ break;
case JS_FUNCTION_TYPE:
JSFunction::cast(this)->JSFunctionPrint(out);
break;
JSValue::cast(this)->value()->Print(out);
break;
case JS_DATE_TYPE:
- JSDate::cast(this)->value()->Print(out);
+ JSDate::cast(this)->JSDatePrint(out);
break;
case CODE_TYPE:
Code::cast(this)->CodePrint(out);
}
+void JSModule::JSModulePrint(FILE* out) {
+ HeapObject::PrintHeader(out, "JSModule");
+ PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - context = ");
+ context()->Print(out);
+ PrintElementsKind(out, this->map()->elements_kind());
+ PrintF(out, " {\n");
+ PrintProperties(out);
+ PrintElements(out);
+ PrintF(out, " }\n");
+}
+
+
static const char* TypeToString(InstanceType type) {
switch (type) {
case INVALID_TYPE: return "INVALID";
case ODDBALL_TYPE: return "ODDBALL";
case JS_GLOBAL_PROPERTY_CELL_TYPE: return "JS_GLOBAL_PROPERTY_CELL";
case SHARED_FUNCTION_INFO_TYPE: return "SHARED_FUNCTION_INFO";
+ case JS_MODULE_TYPE: return "JS_MODULE";
case JS_FUNCTION_TYPE: return "JS_FUNCTION";
case CODE_TYPE: return "CODE";
case JS_ARRAY_TYPE: return "JS_ARRAY";
case JS_OBJECT_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
+ case JS_MODULE_TYPE:
case JS_VALUE_TYPE:
case JS_DATE_TYPE:
case JS_ARRAY_TYPE:
break;
case JS_OBJECT_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
+ case JS_MODULE_TYPE:
case JS_VALUE_TYPE:
case JS_DATE_TYPE:
case JS_ARRAY_TYPE:
// - JSWeakMap
// - JSRegExp
// - JSFunction
+// - JSModule
// - GlobalObject
// - JSGlobalObject
// - JSBuiltinsObject
V(JS_DATE_TYPE) \
V(JS_OBJECT_TYPE) \
V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \
+ V(JS_MODULE_TYPE) \
V(JS_GLOBAL_OBJECT_TYPE) \
V(JS_BUILTINS_OBJECT_TYPE) \
V(JS_GLOBAL_PROXY_TYPE) \
JS_DATE_TYPE,
JS_OBJECT_TYPE,
JS_CONTEXT_EXTENSION_OBJECT_TYPE,
+ JS_MODULE_TYPE,
JS_GLOBAL_OBJECT_TYPE,
JS_BUILTINS_OBJECT_TYPE,
JS_GLOBAL_PROXY_TYPE,
V(JSReceiver) \
V(JSObject) \
V(JSContextExtensionObject) \
+ V(JSModule) \
V(Map) \
V(DescriptorArray) \
V(DeoptimizationInputData) \
V(FixedDoubleArray) \
V(Context) \
V(GlobalContext) \
+ V(ModuleContext) \
V(ScopeInfo) \
V(JSFunction) \
V(Code) \
};
+// Representation for module instance objects.
+class JSModule: public JSObject {
+ public:
+ // [context]: the context holding the module's locals, or undefined if none.
+ DECL_ACCESSORS(context, Object)
+
+ // Casting.
+ static inline JSModule* cast(Object* obj);
+
+ // Dispatched behavior.
+#ifdef OBJECT_PRINT
+ inline void JSModulePrint() {
+ JSModulePrint(stdout);
+ }
+ void JSModulePrint(FILE* out);
+#endif
+#ifdef DEBUG
+ void JSModuleVerify();
+#endif
+
+ // Layout description.
+ static const int kContextOffset = JSObject::kHeaderSize;
+ static const int kSize = kContextOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSModule);
+};
+
+
// JSFunction describes JavaScript functions.
class JSFunction: public JSObject {
public:
Expect(Token::RBRACE, CHECK_OK);
scope->set_end_position(scanner().location().end_pos);
- body->set_block_scope(scope);
+ body->set_scope(scope);
- scope->interface()->Freeze(ok);
+ // Instance objects have to be created ahead of time (before code generation
+ // linking them) because of potentially cyclic references between them.
+ // We create them here, to avoid another pass over the AST.
+ Interface* interface = scope->interface();
+ interface->MakeModule(ok);
ASSERT(ok);
- return factory()->NewModuleLiteral(body, scope->interface());
+ interface->MakeSingleton(Isolate::Current()->factory()->NewJSModule(), ok);
+ ASSERT(ok);
+ interface->Freeze(ok);
+ ASSERT(ok);
+ return factory()->NewModuleLiteral(body, interface);
}
#ifdef DEBUG
if (FLAG_print_interface_details) PrintF("# Url ");
#endif
- return factory()->NewModuleUrl(symbol);
+
+ Module* result = factory()->NewModuleUrl(symbol);
+ Interface* interface = result->interface();
+ interface->MakeSingleton(Isolate::Current()->factory()->NewJSModule(), ok);
+ ASSERT(ok);
+ interface->Freeze(ok);
+ ASSERT(ok);
+ return result;
}
Expect(Token::RBRACE, CHECK_OK);
block_scope->set_end_position(scanner().location().end_pos);
block_scope = block_scope->FinalizeBlockScope();
- body->set_block_scope(block_scope);
+ body->set_scope(block_scope);
return body;
}
top_scope_ = saved_scope;
for_scope->set_end_position(scanner().location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
- body_block->set_block_scope(for_scope);
+ body_block->set_scope(for_scope);
// Parsed for-in loop w/ let declaration.
return loop;
Block* result = factory()->NewBlock(NULL, 2, false);
result->AddStatement(init);
result->AddStatement(loop);
- result->set_block_scope(for_scope);
+ result->set_scope(for_scope);
if (loop) loop->Initialize(NULL, cond, next, body);
return result;
} else {
bool is_var = value->IsUndefined();
bool is_const = value->IsTheHole();
bool is_function = value->IsSharedFunctionInfo();
- bool is_module = value->IsJSObject();
+ bool is_module = value->IsJSModule();
ASSERT(is_var + is_const + is_function + is_module == 1);
if (is_var || is_const) {
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 2);
+ CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 0);
+ CONVERT_ARG_HANDLE_CHECKED(JSModule, instance, 1);
+
+ Context* context;
+ MaybeObject* maybe_context =
+ isolate->heap()->AllocateModuleContext(isolate->context(),
+ scope_info);
+ if (!maybe_context->To(&context)) return maybe_context;
+ // Also initialize the context slot of the instance object.
+ instance->set_context(context);
+ isolate->set_context(context);
+
+ return context;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
HandleScope scope(isolate);
ASSERT(args.length() == 2);
F(PushWithContext, 2, 1) \
F(PushCatchContext, 3, 1) \
F(PushBlockContext, 2, 1) \
+ F(PushModuleContext, 2, 1) \
F(DeleteContextSlot, 2, 1) \
F(LoadContextSlot, 2, 2) \
F(LoadContextSlotNoReferenceError, 2, 2) \
ASSERT(index == scope_info->length());
ASSERT(scope->num_parameters() == scope_info->ParameterCount());
ASSERT(scope->num_stack_slots() == scope_info->StackSlotCount());
- ASSERT(scope->num_heap_slots() == scope_info->ContextLength());
+ ASSERT(scope->num_heap_slots() == scope_info->ContextLength() ||
+ (scope->num_heap_slots() == kVariablePartIndex &&
+ scope_info->ContextLength() == 0));
return scope_info;
}
// Exceptions: temporary variables are never allocated in a context;
// catch-bound variables are always allocated in a context.
if (var->mode() == TEMPORARY) return false;
- if (is_catch_scope() || is_block_scope()) return true;
+ if (is_catch_scope() || is_block_scope() || is_module_scope()) return true;
return var->has_forced_context_allocation() ||
scope_calls_eval_ ||
inner_scope_calls_eval_ ||
// Force allocation of a context for this scope if necessary. For a 'with'
// scope and for a function scope that makes an 'eval' call we need a context,
// even if no local variables were statically allocated in the scope.
- bool must_have_context = is_with_scope() ||
+ // Likewise for modules.
+ bool must_have_context = is_with_scope() || is_module_scope() ||
(is_function_scope() && calls_eval());
// If we didn't allocate any locals in the local context, then we only
bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
switch (variable->location()) {
case Variable::UNALLOCATED:
- globals_.Add(variable->name());
- globals_.Add(variable->binding_needs_init()
- ? isolate()->factory()->the_hole_value()
- : isolate()->factory()->undefined_value());
+ globals_->Add(variable->name());
+ globals_->Add(variable->binding_needs_init()
+ ? isolate()->factory()->the_hole_value()
+ : isolate()->factory()->undefined_value());
break;
case Variable::PARAMETER:
Variable* variable = proxy->var();
switch (variable->location()) {
case Variable::UNALLOCATED: {
- globals_.Add(variable->name());
+ globals_->Add(variable->name());
Handle<SharedFunctionInfo> function =
Compiler::BuildFunctionInfo(declaration->fun(), script());
// Check for stack-overflow exception.
if (function.is_null()) return SetStackOverflow();
- globals_.Add(function);
+ globals_->Add(function);
break;
}
void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
+ Handle<JSModule> instance = declaration->module()->interface()->Instance();
+ ASSERT(!instance.is_null());
+
switch (variable->location()) {
- case Variable::UNALLOCATED:
- // TODO(rossberg): initialize module instance object
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "[ ModuleDeclaration");
+ globals_->Add(variable->name());
+ globals_->Add(instance);
+ Visit(declaration->module());
break;
+ }
case Variable::CONTEXT: {
Comment cmnt(masm_, "[ ModuleDeclaration");
EmitDebugCheckDeclarationContext(variable);
- // TODO(rossberg): initialize module instance object
+ __ Move(ContextOperand(rsi, variable->index()), instance);
+ Visit(declaration->module());
break;
}
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
Scope* declaration_scope = scope()->DeclarationScope();
- if (declaration_scope->is_global_scope()) {
+ if (declaration_scope->is_global_scope() ||
+ declaration_scope->is_module_scope()) {
// Contexts nested in the global context have a canonical empty function
// as their closure, not the anonymous closure containing the global
// code. Pass a smi sentinel and let the runtime look up the empty
--- /dev/null
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-modules --harmony-scoping
+
+// Test basic module linking.
+
+"use strict";
+
+let log = "";
+
+export let x = (log += "1");
+
+export module B = A.B
+
+export module A {
+ export let x = (log += "2");
+ let y = (log += "3");
+ export function f() { log += "5" };
+ export module B {
+ module BB = B;
+ export BB, x;
+ let x = (log += "4");
+ f();
+ let y = (log += "6");
+ }
+ export let z = (log += "7");
+ export module C {
+ export let z = (log += "8");
+ export module D = B
+ export module C = A.C
+ }
+ module D {}
+}
+
+export module M1 {
+ export module A2 = M2;
+ export let x = (log += "9");
+}
+export module M2 {
+ export module A1 = M1;
+ export let x = (log += "0");
+}
+
+assertEquals("object", typeof A);
+assertTrue('x' in A);
+assertFalse('y' in A);
+assertTrue('f' in A);
+assertTrue('B' in A);
+assertTrue('z' in A);
+assertTrue('C' in A);
+assertFalse('D' in A);
+
+assertEquals("object", typeof B);
+assertTrue('BB' in B);
+assertTrue('x' in B);
+assertFalse('y' in B);
+
+assertEquals("object", typeof A.B);
+assertTrue('BB' in A.B);
+assertTrue('x' in A.B);
+assertFalse('y' in A.B);
+
+assertEquals("object", typeof A.B.BB);
+assertTrue('BB' in A.B.BB);
+assertTrue('x' in A.B.BB);
+assertFalse('y' in A.B.BB);
+
+assertEquals("object", typeof A.C);
+assertTrue('z' in A.C);
+assertTrue('D' in A.C);
+assertTrue('C' in A.C);
+
+assertEquals("object", typeof M1);
+assertEquals("object", typeof M2);
+assertTrue('A2' in M1);
+assertTrue('A1' in M2);
+assertEquals("object", typeof M1.A2);
+assertEquals("object", typeof M2.A1);
+assertTrue('A1' in M1.A2);
+assertTrue('A2' in M2.A1);
+assertEquals("object", typeof M1.A2.A1);
+assertEquals("object", typeof M2.A1.A2);
+
+assertSame(B, A.B);
+assertSame(B, B.BB);
+assertSame(B, A.C.D);
+assertSame(A.C, A.C.C);
+assertFalse(A.D === A.C.D);
+
+assertSame(M1, M2.A1);
+assertSame(M2, M1.A2);
+assertSame(M1, M1.A2.A1);
+assertSame(M2, M2.A1.A2);
+
+// TODO(rossberg): inner declarations are not executed yet.
+// assertEquals("1234567890", log);
import i0 from I
import i1, i2, i3, M from I
- import i4, i5 from "http://where"
+ //import i4, i5 from "http://where"
}
module I {
module E1 at "http://where"
module E2 at "http://where";
-module E3 = E1.F
+module E3 = E1
// Check that ASI does not interfere.
"file://local"
import
-x
+vx
,
-y
+vy
from
-"file://local"
+B
module Wrap {
export module External at "external.js"
export module External1 = External
-export module ExternalA = External.A
+//export module ExternalA = External.A
export module InnerExternal {
export module E at "external.js"
}