summaryrefslogtreecommitdiff
path: root/deps/v8/src/torque/implementation-visitor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/torque/implementation-visitor.cc')
-rw-r--r--deps/v8/src/torque/implementation-visitor.cc2116
1 files changed, 1336 insertions, 780 deletions
diff --git a/deps/v8/src/torque/implementation-visitor.cc b/deps/v8/src/torque/implementation-visitor.cc
index 89c0c70416..5b52a31cf3 100644
--- a/deps/v8/src/torque/implementation-visitor.cc
+++ b/deps/v8/src/torque/implementation-visitor.cc
@@ -5,6 +5,7 @@
#include <algorithm>
#include "src/torque/csa-generator.h"
+#include "src/torque/declaration-visitor.h"
#include "src/torque/implementation-visitor.h"
#include "src/torque/parameter-difference.h"
@@ -27,6 +28,7 @@ VisitResult ImplementationVisitor::Visit(Expression* expr) {
const Type* ImplementationVisitor::Visit(Statement* stmt) {
CurrentSourcePosition::Scope scope(stmt->pos);
+ StackScope stack_scope(this);
const Type* result;
switch (stmt->kind) {
#define ENUM_ITEM(name) \
@@ -43,102 +45,53 @@ const Type* ImplementationVisitor::Visit(Statement* stmt) {
return result;
}
-void ImplementationVisitor::Visit(Declaration* decl) {
- CurrentSourcePosition::Scope scope(decl->pos);
- switch (decl->kind) {
-#define ENUM_ITEM(name) \
- case AstNode::Kind::k##name: \
- return Visit(name::cast(decl));
- AST_DECLARATION_NODE_KIND_LIST(ENUM_ITEM)
-#undef ENUM_ITEM
- default:
- UNIMPLEMENTED();
- }
-}
+void ImplementationVisitor::BeginNamespaceFile(Namespace* nspace) {
+ std::ostream& source = nspace->source_stream();
+ std::ostream& header = nspace->header_stream();
-void ImplementationVisitor::Visit(CallableNode* decl,
- const Signature& signature, Statement* body) {
- switch (decl->kind) {
-#define ENUM_ITEM(name) \
- case AstNode::Kind::k##name: \
- return Visit(name::cast(decl), signature, body);
- AST_CALLABLE_NODE_KIND_LIST(ENUM_ITEM)
-#undef ENUM_ITEM
- default:
- UNIMPLEMENTED();
+ for (const std::string& include_path : GlobalContext::CppIncludes()) {
+ source << "#include " << StringLiteralQuote(include_path) << "\n";
}
-}
-
-void ImplementationVisitor::BeginModuleFile(Module* module) {
- std::ostream& source = module->source_stream();
- std::ostream& header = module->header_stream();
- if (module->IsDefault()) {
- source << "#include \"src/torque-assembler.h\"";
- } else {
- source << "#include \"src/builtins/builtins-" +
- DashifyString(module->name()) + "-gen.h\"";
+ for (Namespace* n : GlobalContext::Get().GetNamespaces()) {
+ source << "#include \"torque-generated/builtins-" +
+ DashifyString(n->name()) + "-from-dsl-gen.h\"\n";
}
source << "\n";
- source << "#include \"src/objects/arguments.h\"\n";
- source << "#include \"src/builtins/builtins-utils-gen.h\"\n";
- source << "#include \"src/builtins/builtins.h\"\n";
- source << "#include \"src/code-factory.h\"\n";
- source << "#include \"src/elements-kind.h\"\n";
- source << "#include \"src/heap/factory-inl.h\"\n";
- source << "#include \"src/objects.h\"\n";
- source << "#include \"src/objects/bigint.h\"\n";
-
- source << "#include \"builtins-" + DashifyString(module->name()) +
- "-from-dsl-gen.h\"\n\n";
source << "namespace v8 {\n"
<< "namespace internal {\n"
- << "\n"
- << "using Node = compiler::Node;\n"
<< "\n";
- std::string upper_name(module->name());
+ std::string upper_name(nspace->name());
transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
::toupper);
std::string headerDefine =
std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
header << "#ifndef " << headerDefine << "\n";
header << "#define " << headerDefine << "\n\n";
- if (module->IsDefault()) {
- header << "#include \"src/torque-assembler.h\"";
- } else {
- header << "#include \"src/builtins/builtins-" +
- DashifyString(module->name()) + "-gen.h\"\n";
+ header << "#include \"src/compiler/code-assembler.h\"\n";
+ if (nspace != GlobalContext::GetDefaultNamespace()) {
+ header << "#include \"src/code-stub-assembler.h\"\n";
}
- header << "\n\n ";
+ header << "\n";
header << "namespace v8 {\n"
<< "namespace internal {\n"
<< "\n";
- header << "class " << GetDSLAssemblerName(module) << ": public "
- << GetBaseAssemblerName(module) << " {\n";
+ header << "class " << nspace->ExternalName() << " {\n";
header << " public:\n";
- header << " explicit " << GetDSLAssemblerName(module)
- << "(compiler::CodeAssemblerState* state) : "
- << GetBaseAssemblerName(module) << "(state) {}\n";
-
- header << "\n";
- header << " using Node = compiler::Node;\n";
- header << " template <class T>\n";
- header << " using TNode = compiler::TNode<T>;\n";
- header << " template <class T>\n";
- header << " using SloppyTNode = compiler::SloppyTNode<T>;\n\n";
+ header << " explicit " << nspace->ExternalName()
+ << "(compiler::CodeAssemblerState* state) : state_(state), ca_(state) "
+ "{ USE(state_, ca_); }\n";
}
-void ImplementationVisitor::EndModuleFile(Module* module) {
- std::ostream& source = module->source_stream();
- std::ostream& header = module->header_stream();
-
- DrainSpecializationQueue();
+void ImplementationVisitor::EndNamespaceFile(Namespace* nspace) {
+ std::ostream& source = nspace->source_stream();
+ std::ostream& header = nspace->header_stream();
- std::string upper_name(module->name());
+ std::string upper_name(nspace->name());
transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
::toupper);
std::string headerDefine =
@@ -148,32 +101,28 @@ void ImplementationVisitor::EndModuleFile(Module* module) {
<< "} // namespace v8\n"
<< "\n";
- header << "};\n\n";
+ header << " private:\n"
+ << " compiler::CodeAssemblerState* const state_;\n"
+ << " compiler::CodeAssembler ca_;"
+ << "}; \n\n";
header << "} // namespace internal\n"
<< "} // namespace v8\n"
<< "\n";
header << "#endif // " << headerDefine << "\n";
}
-void ImplementationVisitor::Visit(ModuleDeclaration* decl) {
- Module* module = decl->GetModule();
- Module* saved_module = module_;
- module_ = module;
- Declarations::ModuleScopeActivator scope(declarations(), decl->GetModule());
- for (auto& child : decl->declarations) Visit(child);
- module_ = saved_module;
-}
+void ImplementationVisitor::Visit(NamespaceConstant* decl) {
+ Signature signature{{}, base::nullopt, {{}, false}, 0, decl->type(), {}};
+ const std::string& name = decl->name();
-void ImplementationVisitor::Visit(ConstDeclaration* decl) {
- Signature signature = MakeSignatureFromReturnType(decl->type);
- std::string name = decl->name;
+ BindingsManagersScope bindings_managers_scope;
header_out() << " ";
GenerateFunctionDeclaration(header_out(), "", name, signature, {});
header_out() << ";\n";
GenerateFunctionDeclaration(source_out(),
- GetDSLAssemblerName(CurrentModule()) + "::", name,
+ CurrentNamespace()->ExternalName() + "::", name,
signature, {});
source_out() << " {\n";
@@ -181,7 +130,7 @@ void ImplementationVisitor::Visit(ConstDeclaration* decl) {
assembler_ = CfgAssembler(Stack<const Type*>{});
- VisitResult expression_result = Visit(decl->expression);
+ VisitResult expression_result = Visit(decl->body());
VisitResult return_result =
GenerateImplicitConvert(signature.return_type, expression_result);
@@ -196,13 +145,15 @@ void ImplementationVisitor::Visit(ConstDeclaration* decl) {
source_out() << "}\n\n";
}
-void ImplementationVisitor::Visit(StructDeclaration* decl) {
- header_out() << " struct " << decl->name << " {\n";
- const StructType* struct_type =
- static_cast<const StructType*>(declarations()->LookupType(decl->name));
+void ImplementationVisitor::Visit(TypeAlias* alias) {
+ if (alias->IsRedeclaration()) return;
+ const StructType* struct_type = StructType::DynamicCast(alias->type());
+ if (!struct_type) return;
+ const std::string& name = struct_type->name();
+ header_out() << " struct " << name << " {\n";
for (auto& field : struct_type->fields()) {
- header_out() << " " << field.type->GetGeneratedTypeName();
- header_out() << " " << field.name << ";\n";
+ header_out() << " " << field.name_and_type.type->GetGeneratedTypeName();
+ header_out() << " " << field.name_and_type.name << ";\n";
}
header_out() << "\n std::tuple<";
bool first = true;
@@ -221,10 +172,10 @@ void ImplementationVisitor::Visit(StructDeclaration* decl) {
header_out() << ", ";
}
first = false;
- if (field.type->IsStructType()) {
- header_out() << field.name << ".Flatten()";
+ if (field.name_and_type.type->IsStructType()) {
+ header_out() << field.name_and_type.name << ".Flatten()";
} else {
- header_out() << "std::make_tuple(" << field.name << ")";
+ header_out() << "std::make_tuple(" << field.name_and_type.name << ")";
}
}
header_out() << ");\n";
@@ -232,151 +183,275 @@ void ImplementationVisitor::Visit(StructDeclaration* decl) {
header_out() << " };\n";
}
-void ImplementationVisitor::Visit(TorqueMacroDeclaration* decl,
- const Signature& sig, Statement* body) {
- Signature signature = MakeSignature(decl->signature.get());
- const Type* return_type = signature.return_type;
+VisitResult ImplementationVisitor::InlineMacro(
+ Macro* macro, base::Optional<LocationReference> this_reference,
+ const std::vector<VisitResult>& arguments,
+ const std::vector<Block*> label_blocks) {
+ CurrentScope::Scope current_scope(macro);
+ BindingsManagersScope bindings_managers_scope;
+ CurrentCallable::Scope current_callable(macro);
+ CurrentReturnValue::Scope current_return_value;
+ const Signature& signature = macro->signature();
+ const Type* return_type = macro->signature().return_type;
+ bool can_return = return_type != TypeOracle::GetNeverType();
+
+ CurrentConstructorInfo::Scope current_constructor;
+ if (macro->IsConstructor())
+ CurrentConstructorInfo::Get() = ConstructorInfo{0};
+
+ BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
+ BlockBindings<LocalLabel> label_bindings(&LabelBindingsManager::Get());
+ DCHECK_EQ(macro->signature().parameter_names.size(),
+ arguments.size() + (this_reference ? 1 : 0));
+ DCHECK_EQ(this_reference.has_value(), macro->IsMethod());
+
+ // Bind the this for methods. Methods that modify a struct-type "this" must
+ // only be called if the this is in a variable, in which case the
+ // LocalValue is non-const. Otherwise, the LocalValue used for the parameter
+ // binding is const, and thus read-only, which will cause errors if
+ // modified, e.g. when called by a struct method that sets the structs
+ // fields. This prevents using temporary struct values for anything other
+ // than read operations.
+ if (this_reference) {
+ DCHECK(macro->IsMethod());
+ LocalValue this_value = LocalValue{!this_reference->IsVariableAccess(),
+ this_reference->GetVisitResult()};
+ parameter_bindings.Add(kThisParameterName, this_value);
+ }
+
+ size_t i = 0;
+ for (auto arg : arguments) {
+ if (this_reference && i == signature.implicit_count) i++;
+ const std::string& name = macro->parameter_names()[i++];
+ parameter_bindings.Add(name, LocalValue{true, arg});
+ }
+
+ DCHECK_EQ(label_blocks.size(), signature.labels.size());
+ for (size_t i = 0; i < signature.labels.size(); ++i) {
+ const LabelDeclaration& label_info = signature.labels[i];
+ label_bindings.Add(label_info.name,
+ LocalLabel{label_blocks[i], label_info.types});
+ }
+
+ Block* macro_end;
+ base::Optional<Binding<LocalLabel>> macro_end_binding;
+ if (can_return) {
+ Stack<const Type*> stack = assembler().CurrentStack();
+ std::vector<const Type*> lowered_return_types = LowerType(return_type);
+ stack.PushMany(lowered_return_types);
+ if (!return_type->IsConstexpr()) {
+ SetReturnValue(VisitResult(return_type,
+ stack.TopRange(lowered_return_types.size())));
+ }
+ // The stack copy used to initialize the _macro_end block is only used
+ // as a template for the actual gotos generated by return statements. It
+ // doesn't correspond to any real return values, and thus shouldn't contain
+ // top types, because these would pollute actual return value types that get
+ // unioned with them for return statements, erroneously forcing them to top.
+ for (auto i = stack.begin(); i != stack.end(); ++i) {
+ if ((*i)->IsTopType()) {
+ *i = TopType::cast(*i)->source_type();
+ }
+ }
+ macro_end = assembler().NewBlock(std::move(stack));
+ macro_end_binding.emplace(&LabelBindingsManager::Get(), "_macro_end",
+ LocalLabel{macro_end, {return_type}});
+ } else {
+ SetReturnValue(VisitResult::NeverResult());
+ }
+
+ const Type* result = Visit(*macro->body());
+
+ if (result->IsNever()) {
+ if (!return_type->IsNever() && !macro->HasReturns()) {
+ std::stringstream s;
+ s << "macro " << macro->ReadableName()
+ << " that never returns must have return type never";
+ ReportError(s.str());
+ }
+ } else {
+ if (return_type->IsNever()) {
+ std::stringstream s;
+ s << "macro " << macro->ReadableName()
+ << " has implicit return at end of its declartion but return type "
+ "never";
+ ReportError(s.str());
+ } else if (!macro->signature().return_type->IsVoid()) {
+ std::stringstream s;
+ s << "macro " << macro->ReadableName()
+ << " expects to return a value but doesn't on all paths";
+ ReportError(s.str());
+ }
+ }
+ if (!result->IsNever()) {
+ assembler().Goto(macro_end);
+ }
+
+ if (macro->HasReturns() || !result->IsNever()) {
+ assembler().Bind(macro_end);
+ }
+
+ return GetAndClearReturnValue();
+}
+
+void ImplementationVisitor::VisitMacroCommon(Macro* macro) {
+ // Do not generate code for inlined macros.
+ if (macro->ShouldBeInlined()) {
+ return;
+ }
+
+ CurrentCallable::Scope current_callable(macro);
+ const Signature& signature = macro->signature();
+ const Type* return_type = macro->signature().return_type;
bool can_return = return_type != TypeOracle::GetNeverType();
bool has_return_value =
can_return && return_type != TypeOracle::GetVoidType();
- std::string name = GetGeneratedCallableName(
- decl->name, declarations()->GetCurrentSpecializationTypeNamesVector());
- const TypeVector& list = signature.types();
- Macro* macro = declarations()->LookupMacro(name, list);
- CurrentCallableActivator activator(global_context_, macro, decl);
+ // Struct methods should never generate code, they should always be inlined
+ DCHECK(!macro->IsMethod() ||
+ Method::cast(macro)->aggregate_type()->IsClassType());
- if (body != nullptr) {
- header_out() << " ";
- GenerateMacroFunctionDeclaration(header_out(), "", macro);
- header_out() << ";\n";
+ header_out() << " ";
+ GenerateMacroFunctionDeclaration(header_out(), "", macro);
+ header_out() << ";\n";
- GenerateMacroFunctionDeclaration(
- source_out(), GetDSLAssemblerName(CurrentModule()) + "::", macro);
- source_out() << " {\n";
+ GenerateMacroFunctionDeclaration(
+ source_out(), CurrentNamespace()->ExternalName() + "::", macro);
+ source_out() << " {\n";
- Stack<std::string> lowered_parameters;
- Stack<const Type*> lowered_parameter_types;
+ Stack<std::string> lowered_parameters;
+ Stack<const Type*> lowered_parameter_types;
- for (const std::string& name : macro->parameter_names()) {
- Parameter* parameter = Parameter::cast(declarations()->LookupValue(name));
- const Type* type = parameter->type();
- if (type->IsConstexpr()) {
- parameter->set_value(
- VisitResult(parameter->type(), parameter->external_name()));
- } else {
- LowerParameter(type, parameter->external_name(), &lowered_parameters);
- StackRange range = lowered_parameter_types.PushMany(LowerType(type));
- parameter->set_value(VisitResult(type, range));
- }
- }
+ std::vector<VisitResult> arguments;
- DCHECK_EQ(lowered_parameters.Size(), lowered_parameter_types.Size());
- assembler_ = CfgAssembler(lowered_parameter_types);
+ base::Optional<LocationReference> this_reference;
+ if (Method* method = Method::DynamicCast(macro)) {
+ const Type* this_type = method->aggregate_type();
+ DCHECK(this_type->IsClassType());
+ lowered_parameter_types.Push(this_type);
+ lowered_parameters.Push(ExternalParameterName(kThisParameterName));
+ VisitResult this_result =
+ VisitResult(this_type, lowered_parameters.TopRange(1));
+ // Mark the this as a temporary to prevent assignment to it.
+ this_reference =
+ LocationReference::Temporary(this_result, "this parameter");
+ }
- for (const LabelDeclaration& label_info : sig.labels) {
- Label* label = declarations()->LookupLabel(label_info.name);
- Stack<const Type*> label_input_stack;
- for (Variable* v : label->GetParameters()) {
- label_input_stack.PushMany(LowerType(v->type()));
- }
- CreateBlockForLabel(label, label_input_stack);
- }
+ for (size_t i = 0; i < macro->signature().parameter_names.size(); ++i) {
+ if (this_reference && i == macro->signature().implicit_count) continue;
+ const std::string& name = macro->parameter_names()[i];
+ std::string external_name = ExternalParameterName(name);
+ const Type* type = macro->signature().types()[i];
- Label* macro_end = declarations()->DeclareLabel("macro_end");
- if (can_return) {
- Stack<const Type*> result_stack;
- CreateBlockForLabel(macro_end,
- Stack<const Type*>{LowerType(signature.return_type)});
+ if (type->IsConstexpr()) {
+ arguments.push_back(VisitResult(type, external_name));
+ } else {
+ LowerParameter(type, external_name, &lowered_parameters);
+ StackRange range = lowered_parameter_types.PushMany(LowerType(type));
+ arguments.push_back(VisitResult(type, range));
}
+ }
- const Type* result = Visit(body);
+ DCHECK_EQ(lowered_parameters.Size(), lowered_parameter_types.Size());
+ assembler_ = CfgAssembler(lowered_parameter_types);
- if (result->IsNever()) {
- if (!macro->signature().return_type->IsNever() && !macro->HasReturns()) {
- std::stringstream s;
- s << "macro " << decl->name
- << " that never returns must have return type never";
- ReportError(s.str());
- }
- } else {
- if (macro->signature().return_type->IsNever()) {
- std::stringstream s;
- s << "macro " << decl->name
- << " has implicit return at end of its declartion but return type "
- "never";
- ReportError(s.str());
- } else if (!macro->signature().return_type->IsVoid()) {
- std::stringstream s;
- s << "macro " << decl->name
- << " expects to return a value but doesn't on all paths";
- ReportError(s.str());
- }
- }
- if (!result->IsNever()) {
- GenerateLabelGoto(macro_end);
+ std::vector<Block*> label_blocks;
+ for (const LabelDeclaration& label_info : signature.labels) {
+ Stack<const Type*> label_input_stack;
+ for (const Type* type : label_info.types) {
+ label_input_stack.PushMany(LowerType(type));
}
+ Block* block = assembler().NewBlock(std::move(label_input_stack));
+ label_blocks.push_back(block);
+ }
- for (const LabelDeclaration& label_info : sig.labels) {
- Label* label = declarations()->LookupLabel(label_info.name);
- GenerateLabelBind(label);
- std::vector<std::string> label_parameter_variables;
- for (size_t i = 0; i < label->GetParameterCount(); ++i) {
- label_parameter_variables.push_back(
- ExternalLabelParameterName(label, i));
- }
- assembler().Emit(GotoExternalInstruction{label->external_label_name(),
- label_parameter_variables});
- }
+ VisitResult return_value =
+ InlineMacro(macro, this_reference, arguments, label_blocks);
+ Block* end = assembler().NewBlock();
+ if (return_type != TypeOracle::GetNeverType()) {
+ assembler().Goto(end);
+ }
- if (macro->HasReturns() || !result->IsNever()) {
- GenerateLabelBind(macro_end);
+ for (size_t i = 0; i < label_blocks.size(); ++i) {
+ Block* label_block = label_blocks[i];
+ const LabelDeclaration& label_info = signature.labels[i];
+ assembler().Bind(label_block);
+ std::vector<std::string> label_parameter_variables;
+ for (size_t i = 0; i < label_info.types.size(); ++i) {
+ label_parameter_variables.push_back(
+ ExternalLabelParameterName(label_info.name, i));
}
+ assembler().Emit(GotoExternalInstruction{ExternalLabelName(label_info.name),
+ label_parameter_variables});
+ }
- CSAGenerator csa_generator{assembler().Result(), source_out()};
- base::Optional<Stack<std::string>> values =
- csa_generator.EmitGraph(lowered_parameters);
+ if (return_type != TypeOracle::GetNeverType()) {
+ assembler().Bind(end);
+ }
- assembler_ = base::nullopt;
+ CSAGenerator csa_generator{assembler().Result(), source_out()};
+ base::Optional<Stack<std::string>> values =
+ csa_generator.EmitGraph(lowered_parameters);
- if (has_return_value) {
- source_out() << " return ";
- CSAGenerator::EmitCSAValue(GetAndClearReturnValue(), *values,
- source_out());
- source_out() << ";\n";
- }
- source_out() << "}\n\n";
+ assembler_ = base::nullopt;
+
+ if (has_return_value) {
+ source_out() << " return ";
+ CSAGenerator::EmitCSAValue(return_value, *values, source_out());
+ source_out() << ";\n";
}
+ source_out() << "}\n\n";
+}
+
+void ImplementationVisitor::Visit(Macro* macro) {
+ if (macro->IsExternal()) return;
+ VisitMacroCommon(macro);
+}
+
+void ImplementationVisitor::Visit(Method* method) {
+ DCHECK(!method->IsExternal());
+ VisitMacroCommon(method);
}
namespace {
-std::string AddParameter(Value* parameter, size_t i,
+
+std::string AddParameter(size_t i, Builtin* builtin,
Stack<std::string>* parameters,
- Stack<const Type*>* parameter_types) {
- std::string name = "parameter" + std::to_string(i);
- parameters->Push(name);
- StackRange range = parameter_types->PushMany(LowerType(parameter->type()));
- parameter->set_value(VisitResult(parameter->type(), range));
- return name;
+ Stack<const Type*>* parameter_types,
+ BlockBindings<LocalValue>* parameter_bindings) {
+ const std::string& name = builtin->signature().parameter_names[i];
+ const Type* type = builtin->signature().types()[i];
+ std::string external_name = "parameter" + std::to_string(i);
+ parameters->Push(external_name);
+ StackRange range = parameter_types->PushMany(LowerType(type));
+ parameter_bindings->Add(name, LocalValue{true, VisitResult(type, range)});
+ return external_name;
}
+
} // namespace
-void ImplementationVisitor::Visit(TorqueBuiltinDeclaration* decl,
- const Signature& signature, Statement* body) {
- std::string name = GetGeneratedCallableName(
- decl->name, declarations()->GetCurrentSpecializationTypeNamesVector());
- source_out() << "TF_BUILTIN(" << name << ", "
- << GetDSLAssemblerName(CurrentModule()) << ") {\n";
- Builtin* builtin = declarations()->LookupBuiltin(name);
- CurrentCallableActivator activator(global_context_, builtin, decl);
+void ImplementationVisitor::Visit(Builtin* builtin) {
+ if (builtin->IsExternal()) return;
+ CurrentScope::Scope current_scope(builtin);
+ const std::string& name = builtin->ExternalName();
+ const Signature& signature = builtin->signature();
+ source_out() << "TF_BUILTIN(" << name << ", CodeStubAssembler) {\n"
+ << " compiler::CodeAssemblerState* state_ = state();"
+ << " compiler::CodeAssembler ca_(state());\n";
+
+ CurrentCallable::Scope current_callable(builtin);
+ CurrentReturnValue::Scope current_return_value;
Stack<const Type*> parameter_types;
Stack<std::string> parameters;
+ BindingsManagersScope bindings_managers_scope;
+
+ BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
+
// Context
- Value* val =
- declarations()->LookupValue(decl->signature->parameters.names[0]);
- std::string parameter0 = AddParameter(val, 0, &parameters, &parameter_types);
+ std::string parameter0 = AddParameter(0, builtin, &parameters,
+ &parameter_types, &parameter_bindings);
source_out() << " TNode<Context> " << parameter0
<< " = UncheckedCast<Context>(Parameter("
<< "Descriptor::kContext));\n";
@@ -384,19 +459,13 @@ void ImplementationVisitor::Visit(TorqueBuiltinDeclaration* decl,
size_t first = 1;
if (builtin->IsVarArgsJavaScript()) {
- assert(decl->signature->parameters.has_varargs);
- ExternConstant* arguments =
- ExternConstant::cast(declarations()->LookupValue(
- decl->signature->parameters.arguments_variable));
- std::string arguments_name = arguments->value().constexpr_value();
+ DCHECK(signature.parameter_types.var_args);
source_out()
<< " Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);\n";
source_out() << " CodeStubArguments arguments_impl(this, "
"ChangeInt32ToIntPtr(argc));\n";
- Value* receiver =
- declarations()->LookupValue(decl->signature->parameters.names[1]);
- std::string parameter1 =
- AddParameter(receiver, 1, &parameters, &parameter_types);
+ std::string parameter1 = AddParameter(
+ 1, builtin, &parameters, &parameter_types, &parameter_bindings);
source_out() << " TNode<Object> " << parameter1
<< " = arguments_impl.GetReceiver();\n";
@@ -404,25 +473,28 @@ void ImplementationVisitor::Visit(TorqueBuiltinDeclaration* decl,
<< " = &arguments_impl;\n";
source_out() << "USE(arguments);\n";
source_out() << "USE(" << parameter1 << ");\n";
+ parameter_bindings.Add(
+ *signature.arguments_variable,
+ LocalValue{true,
+ VisitResult(TypeOracle::GetArgumentsType(), "arguments")});
first = 2;
}
- for (size_t i = 0; i < decl->signature->parameters.names.size(); ++i) {
+ for (size_t i = 0; i < signature.parameter_names.size(); ++i) {
if (i < first) continue;
- const std::string& parameter_name = decl->signature->parameters.names[i];
- Value* parameter = declarations()->LookupValue(parameter_name);
- std::string var = AddParameter(parameter, i, &parameters, &parameter_types);
- source_out() << " " << parameter->type()->GetGeneratedTypeName() << " "
- << var << " = "
- << "UncheckedCast<"
- << parameter->type()->GetGeneratedTNodeTypeName()
+ const std::string& parameter_name = signature.parameter_names[i];
+ const Type* type = signature.types()[i];
+ std::string var = AddParameter(i, builtin, &parameters, &parameter_types,
+ &parameter_bindings);
+ source_out() << " " << type->GetGeneratedTypeName() << " " << var << " = "
+ << "UncheckedCast<" << type->GetGeneratedTNodeTypeName()
<< ">(Parameter(Descriptor::k"
<< CamelifyString(parameter_name) << "));\n";
source_out() << " USE(" << var << ");\n";
}
assembler_ = CfgAssembler(parameter_types);
- const Type* body_result = Visit(body);
+ const Type* body_result = Visit(*builtin->body());
if (body_result != TypeOracle::GetNeverType()) {
ReportError("control reaches end of builtin, expected return of a value");
}
@@ -434,8 +506,30 @@ void ImplementationVisitor::Visit(TorqueBuiltinDeclaration* decl,
}
const Type* ImplementationVisitor::Visit(VarDeclarationStatement* stmt) {
+ BlockBindings<LocalValue> block_bindings(&ValueBindingsManager::Get());
+ return Visit(stmt, &block_bindings);
+}
+
+const Type* ImplementationVisitor::Visit(
+ VarDeclarationStatement* stmt, BlockBindings<LocalValue>* block_bindings) {
+ if (!stmt->const_qualified && !stmt->type) {
+ ReportError(
+ "variable declaration is missing type. Only 'const' bindings can "
+ "infer the type.");
+ }
+ // const qualified variables are required to be initialized properly.
+ if (stmt->const_qualified && !stmt->initializer) {
+ ReportError("local constant \"", stmt->name, "\" is not initialized.");
+ }
+
base::Optional<const Type*> type;
- if (stmt->type) type = declarations()->GetType(*stmt->type);
+ if (stmt->type) {
+ type = Declarations::GetType(*stmt->type);
+ if ((*type)->IsConstexpr() && !stmt->const_qualified) {
+ ReportError(
+ "cannot declare variable with constexpr type. Use 'const' instead.");
+ }
+ }
base::Optional<VisitResult> init_result;
if (stmt->initializer) {
StackScope scope(this);
@@ -451,19 +545,17 @@ const Type* ImplementationVisitor::Visit(VarDeclarationStatement* stmt) {
}
TypeVector lowered_types = LowerType(*type);
for (const Type* type : lowered_types) {
- assembler().Emit(PushUninitializedInstruction{type});
+ assembler().Emit(PushUninitializedInstruction{TypeOracle::GetTopType(
+ "unitialized variable '" + stmt->name + "' of type " +
+ type->ToString() + " originally defined at " +
+ PositionAsString(stmt->pos),
+ type)});
}
init_result =
VisitResult(*type, assembler().TopRange(lowered_types.size()));
}
- Variable* var;
- if (stmt->const_qualified) {
- var = declarations()->DeclareVariable(stmt->name, init_result->type(),
- stmt->const_qualified);
- } else {
- var = Variable::cast(declarations()->LookupValue(stmt->name));
- }
- var->set_value(*init_result);
+ block_bindings->Add(stmt->name,
+ LocalValue{stmt->const_qualified, *init_result});
return TypeOracle::GetVoidType();
}
@@ -472,29 +564,11 @@ const Type* ImplementationVisitor::Visit(TailCallStatement* stmt) {
}
VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) {
- Label* true_label;
- Label* false_label;
+ Block* true_block = assembler().NewBlock(assembler().CurrentStack());
+ Block* false_block = assembler().NewBlock(assembler().CurrentStack());
Block* done_block = assembler().NewBlock();
Block* true_conversion_block = assembler().NewBlock();
- {
- Declarations::NodeScopeActivator scope(declarations(), expr->condition);
-
- true_label = declarations()->LookupLabel(kTrueLabelName);
- CreateBlockForLabel(true_label, assembler().CurrentStack());
- false_label = declarations()->LookupLabel(kFalseLabelName);
- CreateBlockForLabel(false_label, assembler().CurrentStack());
- done_block = assembler().NewBlock();
-
- {
- StackScope condition_scope(this);
- VisitResult condition_result = Visit(expr->condition);
- if (!condition_result.type()->IsNever()) {
- condition_result = condition_scope.Yield(GenerateImplicitConvert(
- TypeOracle::GetBoolType(), condition_result));
- assembler().Branch(true_label->block(), false_label->block());
- }
- }
- }
+ GenerateExpressionBranch(expr->condition, true_block, false_block);
VisitResult left;
VisitResult right;
@@ -504,14 +578,14 @@ VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) {
// before evaluating the conditional expression because the common type of
// the result of both the true and false of the condition needs to be known
// to convert both branches to a common type.
- assembler().Bind(true_label->block());
+ assembler().Bind(true_block);
StackScope left_scope(this);
left = Visit(expr->if_true);
assembler().Goto(true_conversion_block);
const Type* common_type;
{
- assembler().Bind(false_label->block());
+ assembler().Bind(false_block);
StackScope right_scope(this);
right = Visit(expr->if_false);
common_type = GetCommonType(left.type(), right.type());
@@ -532,16 +606,16 @@ VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) {
VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
VisitResult left_result;
{
- Declarations::NodeScopeActivator scope(declarations(), expr->left);
- Label* false_label = declarations()->LookupLabel(kFalseLabelName);
- CreateBlockForLabel(false_label, assembler().CurrentStack());
+ Block* false_block = assembler().NewBlock(assembler().CurrentStack());
+ Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
+ kFalseLabelName, LocalLabel{false_block}};
left_result = Visit(expr->left);
if (left_result.type()->IsBool()) {
- Label* true_label = declarations()->LookupLabel(kTrueLabelName);
- assembler().Branch(true_label->block(), false_label->block());
- assembler().Bind(false_label->block());
+ Block* true_block = LookupSimpleLabel(kTrueLabelName);
+ assembler().Branch(true_block, false_block);
+ assembler().Bind(false_block);
} else if (left_result.type()->IsNever()) {
- assembler().Bind(false_label->block());
+ assembler().Bind(false_block);
} else if (!left_result.type()->IsConstexprBool()) {
ReportError(
"expected type bool, constexpr bool, or never on left-hand side of "
@@ -563,9 +637,9 @@ VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
VisitResult right_result = Visit(expr->right);
if (right_result.type()->IsBool()) {
- Label* true_label = declarations()->LookupLabel(kTrueLabelName);
- Label* false_label = declarations()->LookupLabel(kFalseLabelName);
- assembler().Branch(true_label->block(), false_label->block());
+ Block* true_block = LookupSimpleLabel(kTrueLabelName);
+ Block* false_block = LookupSimpleLabel(kFalseLabelName);
+ assembler().Branch(true_block, false_block);
return VisitResult::NeverResult();
} else if (!right_result.type()->IsNever()) {
ReportError(
@@ -577,16 +651,16 @@ VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) {
VisitResult left_result;
{
- Declarations::NodeScopeActivator scope(declarations(), expr->left);
- Label* true_label = declarations()->LookupLabel(kTrueLabelName);
- CreateBlockForLabel(true_label, assembler().CurrentStack());
+ Block* true_block = assembler().NewBlock(assembler().CurrentStack());
+ Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
+ kTrueLabelName, LocalLabel{true_block}};
left_result = Visit(expr->left);
if (left_result.type()->IsBool()) {
- Label* false_label = declarations()->LookupLabel(kFalseLabelName);
- assembler().Branch(true_label->block(), false_label->block());
- assembler().Bind(true_label->block());
+ Block* false_block = LookupSimpleLabel(kFalseLabelName);
+ assembler().Branch(true_block, false_block);
+ assembler().Bind(true_block);
} else if (left_result.type()->IsNever()) {
- assembler().Bind(true_label->block());
+ assembler().Bind(true_block);
} else if (!left_result.type()->IsConstexprBool()) {
ReportError(
"expected type bool, constexpr bool, or never on left-hand side of "
@@ -608,9 +682,9 @@ VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) {
VisitResult right_result = Visit(expr->right);
if (right_result.type()->IsBool()) {
- Label* true_label = declarations()->LookupLabel(kTrueLabelName);
- Label* false_label = declarations()->LookupLabel(kFalseLabelName);
- assembler().Branch(true_label->block(), false_label->block());
+ Block* true_block = LookupSimpleLabel(kTrueLabelName);
+ Block* false_block = LookupSimpleLabel(kFalseLabelName);
+ assembler().Branch(true_block, false_block);
return VisitResult::NeverResult();
} else if (!right_result.type()->IsNever()) {
ReportError(
@@ -654,13 +728,12 @@ VisitResult ImplementationVisitor::Visit(NumberLiteralExpression* expr) {
// TODO(tebbi): Do not silently loose precision; support 64bit literals.
double d = std::stod(expr->number.c_str());
int32_t i = static_cast<int32_t>(d);
- const Type* result_type =
- declarations()->LookupType(CONST_FLOAT64_TYPE_STRING);
+ const Type* result_type = Declarations::LookupType(CONST_FLOAT64_TYPE_STRING);
if (i == d) {
if ((i >> 30) == (i >> 31)) {
- result_type = declarations()->LookupType(CONST_INT31_TYPE_STRING);
+ result_type = Declarations::LookupType(CONST_INT31_TYPE_STRING);
} else {
- result_type = declarations()->LookupType(CONST_INT32_TYPE_STRING);
+ result_type = Declarations::LookupType(CONST_INT32_TYPE_STRING);
}
}
return VisitResult{result_type, expr->number};
@@ -669,7 +742,7 @@ VisitResult ImplementationVisitor::Visit(NumberLiteralExpression* expr) {
VisitResult ImplementationVisitor::Visit(AssumeTypeImpossibleExpression* expr) {
VisitResult result = Visit(expr->expression);
const Type* result_type =
- SubtractType(result.type(), declarations()->GetType(expr->excluded_type));
+ SubtractType(result.type(), Declarations::GetType(expr->excluded_type));
if (result_type->IsNever()) {
ReportError("unreachable code");
}
@@ -691,44 +764,25 @@ VisitResult ImplementationVisitor::GetBuiltinCode(Builtin* builtin) {
"creating function pointers is only allowed for internal builtins with "
"stub linkage");
}
- const Type* type = TypeOracle::GetFunctionPointerType(
+ const Type* type = TypeOracle::GetBuiltinPointerType(
builtin->signature().parameter_types.types,
builtin->signature().return_type);
- assembler().Emit(PushCodePointerInstruction{builtin->name(), type});
+ assembler().Emit(
+ PushBuiltinPointerInstruction{builtin->ExternalName(), type});
return VisitResult(type, assembler().TopRange(1));
}
VisitResult ImplementationVisitor::Visit(IdentifierExpression* expr) {
StackScope scope(this);
- std::string name = expr->name;
- if (expr->generic_arguments.size() != 0) {
- GenericList* generic_list = declarations()->LookupGeneric(expr->name);
- for (Generic* generic : generic_list->list()) {
- TypeVector specialization_types = GetTypeVector(expr->generic_arguments);
- name = GetGeneratedCallableName(name, specialization_types);
- CallableNode* callable = generic->declaration()->callable;
- QueueGenericSpecialization({generic, specialization_types}, callable,
- callable->signature.get(),
- generic->declaration()->body);
- }
- }
-
- if (Builtin* builtin = Builtin::DynamicCast(declarations()->Lookup(name))) {
- return scope.Yield(GetBuiltinCode(builtin));
- }
-
return scope.Yield(GenerateFetchFromLocation(GetLocationReference(expr)));
}
const Type* ImplementationVisitor::Visit(GotoStatement* stmt) {
- Label* label = declarations()->LookupLabel(stmt->label);
-
- if (stmt->arguments.size() != label->GetParameterCount()) {
- std::stringstream stream;
- stream << "goto to label has incorrect number of parameters (expected "
- << std::to_string(label->GetParameterCount()) << " found "
- << std::to_string(stmt->arguments.size()) << ")";
- ReportError(stream.str());
+ LocalLabel* label = LookupLabel(stmt->label);
+ size_t parameter_count = label->parameter_types.size();
+ if (stmt->arguments.size() != parameter_count) {
+ ReportError("goto to label has incorrect number of parameters (expected ",
+ parameter_count, " found ", stmt->arguments.size(), ")");
}
size_t i = 0;
@@ -736,13 +790,12 @@ const Type* ImplementationVisitor::Visit(GotoStatement* stmt) {
for (Expression* e : stmt->arguments) {
StackScope scope(this);
VisitResult result = Visit(e);
- Variable* var = label->GetParameter(i++);
- result = GenerateImplicitConvert(var->type(), result);
+ const Type* parameter_type = label->parameter_types[i++];
+ result = GenerateImplicitConvert(parameter_type, result);
arguments.Extend(scope.Yield(result).stack_range());
}
- GenerateLabelGoto(label, arguments);
- label->MarkUsed();
+ assembler().Goto(label->block, arguments.Size());
return TypeOracle::GetNeverType();
}
@@ -767,11 +820,7 @@ const Type* ImplementationVisitor::Visit(IfStatement* stmt) {
expression_result.constexpr_value(), true_block, false_block});
assembler().Bind(true_block);
- const Type* left_result;
- {
- StackScope stack_scope(this);
- left_result = Visit(stmt->if_true);
- }
+ const Type* left_result = Visit(stmt->if_true);
if (left_result == TypeOracle::GetVoidType()) {
assembler().Goto(done_block);
}
@@ -779,7 +828,6 @@ const Type* ImplementationVisitor::Visit(IfStatement* stmt) {
assembler().Bind(false_block);
const Type* right_result = TypeOracle::GetVoidType();
if (has_else) {
- StackScope stack_scope(this);
right_result = Visit(*stmt->if_false);
}
if (right_result == TypeOracle::GetVoidType()) {
@@ -799,30 +847,40 @@ const Type* ImplementationVisitor::Visit(IfStatement* stmt) {
}
return left_result;
} else {
- Label* true_label = nullptr;
- Label* false_label = nullptr;
- {
- Declarations::NodeScopeActivator scope(declarations(), &*stmt->condition);
- true_label = declarations()->LookupLabel(kTrueLabelName);
- CreateBlockForLabel(true_label, assembler().CurrentStack());
- false_label = declarations()->LookupLabel(kFalseLabelName);
- CreateBlockForLabel(false_label, assembler().CurrentStack());
- }
+ Block* true_block = assembler().NewBlock(assembler().CurrentStack(),
+ IsDeferred(stmt->if_true));
+ Block* false_block =
+ assembler().NewBlock(assembler().CurrentStack(),
+ stmt->if_false && IsDeferred(*stmt->if_false));
+ GenerateExpressionBranch(stmt->condition, true_block, false_block);
Block* done_block;
bool live = false;
if (has_else) {
done_block = assembler().NewBlock();
} else {
- done_block = false_label->block();
+ done_block = false_block;
live = true;
}
- std::vector<Statement*> blocks = {stmt->if_true};
- std::vector<Label*> labels = {true_label, false_label};
- if (has_else) blocks.push_back(*stmt->if_false);
- if (GenerateExpressionBranch(stmt->condition, labels, blocks, done_block)) {
- live = true;
+
+ assembler().Bind(true_block);
+ {
+ const Type* result = Visit(stmt->if_true);
+ if (result == TypeOracle::GetVoidType()) {
+ live = true;
+ assembler().Goto(done_block);
+ }
}
+
+ if (has_else) {
+ assembler().Bind(false_block);
+ const Type* result = Visit(*stmt->if_false);
+ if (result == TypeOracle::GetVoidType()) {
+ live = true;
+ assembler().Goto(done_block);
+ }
+ }
+
if (live) {
assembler().Bind(done_block);
}
@@ -831,42 +889,41 @@ const Type* ImplementationVisitor::Visit(IfStatement* stmt) {
}
const Type* ImplementationVisitor::Visit(WhileStatement* stmt) {
- Label* body_label = nullptr;
- Label* exit_label = nullptr;
- {
- Declarations::NodeScopeActivator scope(declarations(), stmt->condition);
- body_label = declarations()->LookupLabel(kTrueLabelName);
- CreateBlockForLabel(body_label, assembler().CurrentStack());
- exit_label = declarations()->LookupLabel(kFalseLabelName);
- CreateBlockForLabel(exit_label, assembler().CurrentStack());
- }
+ Block* body_block = assembler().NewBlock(assembler().CurrentStack());
+ Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
Block* header_block = assembler().NewBlock();
assembler().Goto(header_block);
assembler().Bind(header_block);
+ GenerateExpressionBranch(stmt->condition, body_block, exit_block);
- Declarations::NodeScopeActivator scope(declarations(), stmt->body);
- BreakContinueActivator activator(global_context_, exit_label->block(),
- header_block);
-
- GenerateExpressionBranch(stmt->condition, {body_label, exit_label},
- {stmt->body}, header_block);
+ assembler().Bind(body_block);
+ {
+ BreakContinueActivator activator{exit_block, header_block};
+ const Type* body_result = Visit(stmt->body);
+ if (body_result != TypeOracle::GetNeverType()) {
+ assembler().Goto(header_block);
+ }
+ }
- GenerateLabelBind(exit_label);
+ assembler().Bind(exit_block);
return TypeOracle::GetVoidType();
}
const Type* ImplementationVisitor::Visit(BlockStatement* block) {
- Declarations::NodeScopeActivator scope(declarations(), block);
+ BlockBindings<LocalValue> block_bindings(&ValueBindingsManager::Get());
const Type* type = TypeOracle::GetVoidType();
for (Statement* s : block->statements) {
+ CurrentSourcePosition::Scope source_position(s->pos);
if (type->IsNever()) {
- std::stringstream stream;
- stream << "statement after non-returning statement";
- ReportError(stream.str());
+ ReportError("statement after non-returning statement");
+ }
+ if (auto* var_declaration = VarDeclarationStatement::DynamicCast(s)) {
+ type = Visit(var_declaration, &block_bindings);
+ } else {
+ type = Visit(s);
}
- type = Visit(s);
}
return type;
}
@@ -877,7 +934,9 @@ const Type* ImplementationVisitor::Visit(DebugStatement* stmt) {
stmt->reason + "' at " +
PositionAsString(stmt->pos)});
#endif
- assembler().Emit(DebugBreakInstruction{stmt->never_continues});
+ assembler().Emit(AbortInstruction{stmt->never_continues
+ ? AbortInstruction::Kind::kUnreachable
+ : AbortInstruction::Kind::kDebugBreak});
if (stmt->never_continues) {
return TypeOracle::GetNeverType();
} else {
@@ -918,33 +977,17 @@ const Type* ImplementationVisitor::Visit(AssertStatement* stmt) {
// isn't trivial up-front. Secondly, on failure, the assert text should be
// the corresponding Torque code, not the -gen.cc code, which would be the
// case when using CSA_ASSERT_XXX.
- Label* true_label = nullptr;
- Label* false_label = nullptr;
- Declarations::NodeScopeActivator scope(declarations(), stmt->expression);
- true_label = declarations()->LookupLabel(kTrueLabelName);
- CreateBlockForLabel(true_label, assembler().CurrentStack());
- false_label = declarations()->LookupLabel(kFalseLabelName);
- CreateBlockForLabel(false_label, assembler().CurrentStack());
-
- VisitResult expression_result = Visit(stmt->expression);
- if (expression_result.type() == TypeOracle::GetBoolType()) {
- GenerateBranch(expression_result, true_label, false_label);
- } else {
- if (expression_result.type() != TypeOracle::GetNeverType()) {
- std::stringstream s;
- s << "unexpected return type " << *expression_result.type()
- << " for branch expression";
- ReportError(s.str());
- }
- }
+ Block* true_block = assembler().NewBlock(assembler().CurrentStack());
+ Block* false_block = assembler().NewBlock(assembler().CurrentStack(), true);
+ GenerateExpressionBranch(stmt->expression, true_block, false_block);
- GenerateLabelBind(false_label);
- assembler().Emit(PrintConstantStringInstruction{
- "assert '" + FormatAssertSource(stmt->source) + "' failed at " +
- PositionAsString(stmt->pos)});
- assembler().Emit(DebugBreakInstruction{true});
+ assembler().Bind(false_block);
- GenerateLabelBind(true_label);
+ assembler().Emit(AbortInstruction{
+ AbortInstruction::Kind::kAssertionFailure,
+ "Torque assert '" + FormatAssertSource(stmt->source) + "' failed"});
+
+ assembler().Bind(true_block);
}
return TypeOracle::GetVoidType();
}
@@ -955,15 +998,14 @@ const Type* ImplementationVisitor::Visit(ExpressionStatement* stmt) {
}
const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
- Callable* current_callable = global_context_.GetCurrentCallable();
+ Callable* current_callable = CurrentCallable::Get();
if (current_callable->signature().return_type->IsNever()) {
std::stringstream s;
s << "cannot return from a function with return type never";
ReportError(s.str());
}
- Label* end = current_callable->IsMacro()
- ? declarations()->LookupLabel("macro_end")
- : nullptr;
+ LocalLabel* end =
+ current_callable->IsMacro() ? LookupLabel("_macro_end") : nullptr;
if (current_callable->HasReturnValue()) {
if (!stmt->value) {
std::stringstream s;
@@ -1002,9 +1044,6 @@ const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
}
const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
- Declarations::NodeScopeActivator scope(declarations(), stmt);
- StackScope stack_scope(this);
-
VisitResult expression_result = Visit(stmt->iterable);
VisitResult begin = stmt->begin
? Visit(*stmt->begin)
@@ -1027,8 +1066,7 @@ const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
assembler().Bind(header_block);
- BreakContinueActivator activator(global_context_, exit_block,
- increment_block);
+ BreakContinueActivator activator(exit_block, increment_block);
{
StackScope comparison_scope(this);
@@ -1046,22 +1084,20 @@ const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
assembler().Bind(body_block);
{
- StackScope body_scope(this);
-
VisitResult element_result;
{
StackScope element_scope(this);
VisitResult result = GenerateCall("[]", {{expression_result, index}, {}});
if (stmt->var_declaration->type) {
const Type* declared_type =
- declarations()->GetType(*stmt->var_declaration->type);
+ Declarations::GetType(*stmt->var_declaration->type);
result = GenerateImplicitConvert(declared_type, result);
}
element_result = element_scope.Yield(result);
}
- Variable* element_var = Variable::cast(
- declarations()->LookupValue(stmt->var_declaration->name));
- element_var->set_value(element_result);
+ Binding<LocalValue> element_var_binding{&ValueBindingsManager::Get(),
+ stmt->var_declaration->name,
+ LocalValue{true, element_result}};
Visit(stmt->body);
}
assembler().Goto(increment_block);
@@ -1082,63 +1118,95 @@ const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
return TypeOracle::GetVoidType();
}
+VisitResult ImplementationVisitor::TemporaryUninitializedStruct(
+ const StructType* struct_type, const std::string& reason) {
+ StackRange range = assembler().TopRange(0);
+ for (const Field& f : struct_type->fields()) {
+ if (const StructType* struct_type =
+ StructType::DynamicCast(f.name_and_type.type)) {
+ range.Extend(
+ TemporaryUninitializedStruct(struct_type, reason).stack_range());
+ } else {
+ std::string descriptor = "unitialized field '" + f.name_and_type.name +
+ "' declared at " + PositionAsString(f.pos) +
+ " (" + reason + ")";
+ TypeVector lowered_types = LowerType(f.name_and_type.type);
+ for (const Type* type : lowered_types) {
+ assembler().Emit(PushUninitializedInstruction{
+ TypeOracle::GetTopType(descriptor, type)});
+ }
+ range.Extend(assembler().TopRange(lowered_types.size()));
+ }
+ }
+ return VisitResult(struct_type, range);
+}
+
VisitResult ImplementationVisitor::Visit(TryLabelExpression* expr) {
+ size_t parameter_count = expr->label_block->parameters.names.size();
+ std::vector<VisitResult> parameters;
+
+ Block* label_block = nullptr;
Block* done_block = assembler().NewBlock();
VisitResult try_result;
- Label* label = nullptr;
- // Output labels for the goto handlers and for the merge after the try.
{
- // Activate a new scope to see handler labels
- Declarations::NodeScopeActivator scope(declarations(), expr);
- {
- LabelBlock* block = expr->label_block;
- CurrentSourcePosition::Scope source_position(block->pos);
- label = declarations()->LookupLabel(block->label);
-
- Declarations::NodeScopeActivator scope(declarations(), block->body);
- Stack<const Type*> label_input_stack = assembler().CurrentStack();
- for (Variable* v : label->GetParameters()) {
- StackRange range = label_input_stack.PushMany(LowerType(v->type()));
- v->set_value(VisitResult(v->type(), range));
- v->Define();
+ CurrentSourcePosition::Scope source_position(expr->label_block->pos);
+ if (expr->label_block->parameters.has_varargs) {
+ ReportError("cannot use ... for label parameters");
+ }
+ Stack<const Type*> label_input_stack = assembler().CurrentStack();
+ TypeVector parameter_types;
+ for (size_t i = 0; i < parameter_count; ++i) {
+ const Type* type =
+ Declarations::GetType(expr->label_block->parameters.types[i]);
+ parameter_types.push_back(type);
+ if (type->IsConstexpr()) {
+ ReportError("no constexpr type allowed for label arguments");
}
- CreateBlockForLabel(label, label_input_stack);
+ StackRange range = label_input_stack.PushMany(LowerType(type));
+ parameters.push_back(VisitResult(type, range));
}
+ label_block = assembler().NewBlock(label_input_stack,
+ IsDeferred(expr->label_block->body));
+
+ Binding<LocalLabel> label_binding{&LabelBindingsManager::Get(),
+ expr->label_block->label,
+ LocalLabel{label_block, parameter_types}};
// Visit try
- {
- StackScope stack_scope(this);
- try_result = Visit(expr->try_expression);
- if (try_result.type() != TypeOracle::GetNeverType()) {
- try_result = stack_scope.Yield(try_result);
- assembler().Goto(done_block);
- }
+ StackScope stack_scope(this);
+ try_result = Visit(expr->try_expression);
+ if (try_result.type() != TypeOracle::GetNeverType()) {
+ try_result = stack_scope.Yield(try_result);
+ assembler().Goto(done_block);
}
}
- if (label->IsUsed()) {
- // Visit and output the code for the label block. If the label block falls
- // through, then the try must not return a value. Also, if the try doesn't
- // fall through, but the label does, then overall the try-label block
- // returns type void.
- GenerateLabelBind(label);
- const Type* label_result;
- {
- StackScope stack_scope(this);
- label_result = Visit(expr->label_block->body);
- }
- if (!try_result.type()->IsVoidOrNever() && label_result->IsVoid()) {
- ReportError(
- "otherwise clauses cannot fall through in a non-void expression");
- }
- if (label_result != TypeOracle::GetNeverType()) {
- assembler().Goto(done_block);
- }
- if (label_result->IsVoid() && try_result.type()->IsNever()) {
- try_result =
- VisitResult(TypeOracle::GetVoidType(), try_result.stack_range());
+ // Visit and output the code for the label block. If the label block falls
+ // through, then the try must not return a value. Also, if the try doesn't
+ // fall through, but the label does, then overall the try-label block
+ // returns type void.
+ assembler().Bind(label_block);
+ const Type* label_result;
+ {
+ BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
+ for (size_t i = 0; i < parameter_count; ++i) {
+ parameter_bindings.Add(expr->label_block->parameters.names[i],
+ LocalValue{true, parameters[i]});
}
+
+ label_result = Visit(expr->label_block->body);
+ }
+ if (!try_result.type()->IsVoidOrNever() && label_result->IsVoid()) {
+ ReportError(
+ "otherwise clauses cannot fall through in a non-void expression");
+ }
+ if (label_result != TypeOracle::GetNeverType()) {
+ assembler().Goto(done_block);
+ }
+ if (label_result->IsVoid() && try_result.type()->IsNever()) {
+ try_result =
+ VisitResult(TypeOracle::GetVoidType(), try_result.stack_range());
}
if (!try_result.type()->IsNever()) {
@@ -1151,34 +1219,106 @@ VisitResult ImplementationVisitor::Visit(StatementExpression* expr) {
return VisitResult{Visit(expr->statement), assembler().TopRange(0)};
}
+VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
+ StackScope stack_scope(this);
+ const Type* type = Declarations::GetType(expr->type);
+ const ClassType* class_type = ClassType::DynamicCast(type);
+ if (class_type == nullptr) {
+ ReportError("type for new expression must be a class, \"", *type,
+ "\" is not");
+ }
+
+ // In order to ensure "atomicity" of object allocation, a class' constructors
+ // operate on a per-class internal struct rather than the class directly until
+ // the constructor has successfully completed and all class members are
+ // available. Create the appropriate unitialized struct and pass it to the
+ // matching class constructor with the arguments that were passed to new{}
+ StructType* class_this_struct = class_type->struct_type();
+ VisitResult unitialized_struct = TemporaryUninitializedStruct(
+ class_this_struct,
+ "it's not set in the constructor for class " + class_type->name());
+ Arguments constructor_arguments;
+ for (auto p : expr->parameters) {
+ constructor_arguments.parameters.push_back(Visit(p));
+ }
+ LocationReference unitialized_struct_ref =
+ LocationReference::VariableAccess(unitialized_struct);
+ Callable* callable =
+ LookupConstructor(unitialized_struct_ref, constructor_arguments, {});
+ GenerateCall(callable, unitialized_struct_ref, constructor_arguments,
+ {class_type}, false);
+ VisitResult new_struct_result = unitialized_struct;
+
+ // Output the code to generate an unitialized object of the class size in the
+ // GC heap.
+ Arguments allocate_arguments;
+ allocate_arguments.parameters.push_back(VisitResult(
+ TypeOracle::GetConstInt31Type(), std::to_string(class_type->size())));
+ VisitResult allocate_result =
+ GenerateCall("%Allocate", allocate_arguments, {class_type}, false);
+ DCHECK(allocate_result.IsOnStack());
+
+ // Fill in the fields of the newly allocated class by copying the values
+ // from the struct that was built by the constructor. So that the generaeted
+ // code is a bit more readable, assign the values from the first class
+ // member to the last, in order. To do this, first build a list of fields
+ // to assign to in reverse order by visiting the class heirarchy.
+ std::vector<std::pair<const Field*, VisitResult>> store_pairs;
+ const ClassType* current_class = class_type;
+ while (current_class != nullptr) {
+ auto& fields = current_class->fields();
+ for (auto i = fields.rbegin(); i != fields.rend(); ++i) {
+ store_pairs.push_back(std::make_pair(
+ &*i, ProjectStructField(new_struct_result, i->name_and_type.name)));
+ }
+ current_class = current_class->GetSuperClass();
+ if (current_class) {
+ new_struct_result = ProjectStructField(new_struct_result,
+ kConstructorStructSuperFieldName);
+ }
+ }
+
+ // Now that the reversed list of fields and the assignment VisitResults are
+ // available, emit the copies in reverse order of the reversed list to
+ // produce the class field assignments in the expected order.
+ for (auto i = store_pairs.rbegin(); i != store_pairs.rend(); ++i) {
+ assembler().Emit(
+ PeekInstruction(allocate_result.stack_range().begin(), class_type));
+ assembler().Emit(PeekInstruction(i->second.stack_range().begin(),
+ i->first->name_and_type.type));
+ assembler().Emit(
+ StoreObjectFieldInstruction(class_type, i->first->name_and_type.name));
+ }
+
+ return stack_scope.Yield(allocate_result);
+}
+
const Type* ImplementationVisitor::Visit(BreakStatement* stmt) {
- Block* break_block = global_context_.GetCurrentBreak();
- if (break_block == nullptr) {
+ base::Optional<Binding<LocalLabel>*> break_label = TryLookupLabel("_break");
+ if (!break_label) {
ReportError("break used outside of loop");
}
- assembler().Goto(break_block);
+ assembler().Goto((*break_label)->block);
return TypeOracle::GetNeverType();
}
const Type* ImplementationVisitor::Visit(ContinueStatement* stmt) {
- Block* continue_block = global_context_.GetCurrentContinue();
- if (continue_block == nullptr) {
+ base::Optional<Binding<LocalLabel>*> continue_label =
+ TryLookupLabel("_continue");
+ if (!continue_label) {
ReportError("continue used outside of loop");
}
- assembler().Goto(continue_block);
+ assembler().Goto((*continue_label)->block);
return TypeOracle::GetNeverType();
}
const Type* ImplementationVisitor::Visit(ForLoopStatement* stmt) {
- Declarations::NodeScopeActivator scope(declarations(), stmt);
- StackScope stack_scope(this);
+ BlockBindings<LocalValue> loop_bindings(&ValueBindingsManager::Get());
- if (stmt->var_declaration) Visit(*stmt->var_declaration);
+ if (stmt->var_declaration) Visit(*stmt->var_declaration, &loop_bindings);
- Label* body_label = declarations()->LookupLabel(kTrueLabelName);
- CreateBlockForLabel(body_label, assembler().CurrentStack());
- Label* exit_label = declarations()->LookupLabel(kFalseLabelName);
- CreateBlockForLabel(exit_label, assembler().CurrentStack());
+ Block* body_block = assembler().NewBlock(assembler().CurrentStack());
+ Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
Block* header_block = assembler().NewBlock();
assembler().Goto(header_block);
@@ -1197,83 +1337,64 @@ const Type* ImplementationVisitor::Visit(ForLoopStatement* stmt) {
continue_block = action_block;
}
- BreakContinueActivator activator(global_context_, exit_label->block(),
- continue_block);
-
- std::vector<Label*> labels = {body_label, exit_label};
- bool generate_action = true;
if (stmt->test) {
- generate_action = GenerateExpressionBranch(*stmt->test, labels,
- {stmt->body}, continue_block);
+ GenerateExpressionBranch(*stmt->test, body_block, exit_block);
} else {
- GenerateLabelGoto(body_label);
- generate_action =
- GenerateLabeledStatementBlocks({stmt->body}, labels, continue_block);
+ assembler().Goto(body_block);
}
- if (generate_action && stmt->action) {
+ assembler().Bind(body_block);
+ {
+ BreakContinueActivator activator(exit_block, continue_block);
+ const Type* body_result = Visit(stmt->body);
+ if (body_result != TypeOracle::GetNeverType()) {
+ assembler().Goto(continue_block);
+ }
+ }
+
+ if (stmt->action) {
assembler().Bind(action_block);
- Visit(*stmt->action);
- assembler().Goto(header_block);
+ const Type* action_result = Visit(*stmt->action);
+ if (action_result != TypeOracle::GetNeverType()) {
+ assembler().Goto(header_block);
+ }
}
- GenerateLabelBind(exit_label);
+ assembler().Bind(exit_block);
return TypeOracle::GetVoidType();
}
void ImplementationVisitor::GenerateImplementation(const std::string& dir,
- Module* module) {
- std::string new_source(module->source());
+ Namespace* nspace) {
+ std::string new_source(nspace->source());
std::string base_file_name =
- "builtins-" + DashifyString(module->name()) + "-from-dsl-gen";
+ "builtins-" + DashifyString(nspace->name()) + "-from-dsl-gen";
std::string source_file_name = dir + "/" + base_file_name + ".cc";
ReplaceFileContentsIfDifferent(source_file_name, new_source);
- std::string new_header(module->header());
+ std::string new_header(nspace->header());
std::string header_file_name = dir + "/" + base_file_name + ".h";
ReplaceFileContentsIfDifferent(header_file_name, new_header);
}
-std::string ImplementationVisitor::GetBaseAssemblerName(Module* module) {
- if (module == global_context_.GetDefaultModule()) {
- return "TorqueAssembler";
- } else {
- std::string assembler_name(CamelifyString(module->name()) +
- "BuiltinsAssembler");
- return assembler_name;
- }
-}
-
-std::string ImplementationVisitor::GetDSLAssemblerName(Module* module) {
- std::string assembler_name(CamelifyString(module->name()) +
- "BuiltinsFromDSLAssembler");
- return assembler_name;
-}
-
void ImplementationVisitor::GenerateMacroFunctionDeclaration(
std::ostream& o, const std::string& macro_prefix, Macro* macro) {
- GenerateFunctionDeclaration(o, macro_prefix, macro->name(),
+ GenerateFunctionDeclaration(o, macro_prefix, macro->ExternalName(),
macro->signature(), macro->parameter_names());
}
void ImplementationVisitor::GenerateFunctionDeclaration(
std::ostream& o, const std::string& macro_prefix, const std::string& name,
const Signature& signature, const NameVector& parameter_names) {
- if (global_context_.verbose()) {
+ if (GlobalContext::verbose()) {
std::cout << "generating source for declaration " << name << "\n";
}
- // Quite a hack here. Make sure that TNode is namespace qualified if the
- // macro/constant name is also qualified.
- std::string return_type_name(signature.return_type->GetGeneratedTypeName());
- if (const StructType* struct_type =
- StructType::DynamicCast(signature.return_type)) {
- o << GetDSLAssemblerName(struct_type->module()) << "::";
- } else if (macro_prefix != "" && (return_type_name.length() > 5) &&
- (return_type_name.substr(0, 5) == "TNode")) {
- o << "compiler::";
+ if (signature.return_type->IsVoidOrNever()) {
+ o << "void";
+ } else {
+ o << signature.return_type->GetGeneratedTypeName();
}
- o << return_type_name;
o << " " << macro_prefix << name << "(";
DCHECK_EQ(signature.types().size(), parameter_names.size());
@@ -1283,29 +1404,27 @@ void ImplementationVisitor::GenerateFunctionDeclaration(
if (!first) {
o << ", ";
}
- const Parameter* parameter =
- Parameter::cast(declarations()->LookupValue(name));
const Type* parameter_type = *type_iterator;
const std::string& generated_type_name =
parameter_type->GetGeneratedTypeName();
- o << generated_type_name << " " << parameter->external_name();
+ o << generated_type_name << " " << ExternalParameterName(name);
type_iterator++;
first = false;
}
for (const LabelDeclaration& label_info : signature.labels) {
- Label* label = declarations()->LookupLabel(label_info.name);
if (!first) {
o << ", ";
}
- o << "Label* " << label->external_label_name();
+ o << "compiler::CodeAssemblerLabel* " << ExternalLabelName(label_info.name);
size_t i = 0;
- for (Variable* var : label->GetParameters()) {
- std::string generated_type_name("TVariable<");
- generated_type_name += var->type()->GetGeneratedTNodeTypeName();
+ for (const Type* type : label_info.types) {
+ std::string generated_type_name("compiler::TypedCodeAssemblerVariable<");
+ generated_type_name += type->GetGeneratedTNodeTypeName();
generated_type_name += ">*";
o << ", ";
- o << generated_type_name << " " << ExternalLabelParameterName(label, i);
+ o << generated_type_name << " "
+ << ExternalLabelParameterName(label_info.name, i);
++i;
}
}
@@ -1315,107 +1434,150 @@ void ImplementationVisitor::GenerateFunctionDeclaration(
namespace {
-void PrintMacroSignatures(std::stringstream& s, const std::string& name,
- const std::vector<Macro*>& macros) {
- for (Macro* m : macros) {
- s << "\n " << name;
- PrintSignature(s, m->signature(), false);
- }
-}
-
-void FailMacroLookup(const std::string& reason, const std::string& name,
- const Arguments& arguments,
- const std::vector<Macro*>& candidates) {
+void FailCallableLookup(const std::string& reason, const QualifiedName& name,
+ const TypeVector& parameter_types,
+ const std::vector<Binding<LocalLabel>*>& labels,
+ const std::vector<Signature>& candidates) {
std::stringstream stream;
- stream << "\n"
- << reason << ": \n " << name << "("
- << arguments.parameters.GetTypeVector() << ")";
- if (arguments.labels.size() != 0) {
+ stream << "\n" << reason << ": \n " << name << "(" << parameter_types << ")";
+ if (labels.size() != 0) {
stream << " labels ";
- for (auto l : arguments.labels) {
- PrintLabel(stream, *l, false);
+ for (size_t i = 0; i < labels.size(); ++i) {
+ stream << labels[i]->name() << "(" << labels[i]->parameter_types << ")";
}
}
stream << "\ncandidates are:";
- PrintMacroSignatures(stream, name, candidates);
+ for (const Signature& signature : candidates) {
+ stream << "\n " << name;
+ PrintSignature(stream, signature, false);
+ }
ReportError(stream.str());
}
+Callable* GetOrCreateSpecialization(const SpecializationKey& key) {
+ if (base::Optional<Callable*> specialization =
+ key.generic->GetSpecialization(key.specialized_types)) {
+ return *specialization;
+ }
+ return DeclarationVisitor().SpecializeImplicit(key);
+}
+
} // namespace
-Callable* ImplementationVisitor::LookupCall(
- const std::string& name, const Arguments& arguments,
+base::Optional<Binding<LocalValue>*> ImplementationVisitor::TryLookupLocalValue(
+ const std::string& name) {
+ return ValueBindingsManager::Get().TryLookup(name);
+}
+
+base::Optional<Binding<LocalLabel>*> ImplementationVisitor::TryLookupLabel(
+ const std::string& name) {
+ return LabelBindingsManager::Get().TryLookup(name);
+}
+
+Binding<LocalLabel>* ImplementationVisitor::LookupLabel(
+ const std::string& name) {
+ base::Optional<Binding<LocalLabel>*> label = TryLookupLabel(name);
+ if (!label) ReportError("cannot find label ", name);
+ return *label;
+}
+
+Block* ImplementationVisitor::LookupSimpleLabel(const std::string& name) {
+ LocalLabel* label = LookupLabel(name);
+ if (!label->parameter_types.empty()) {
+ ReportError("label ", name,
+ "was expected to have no parameters, but has parameters (",
+ label->parameter_types, ")");
+ }
+ return label->block;
+}
+
+template <class Container>
+Callable* ImplementationVisitor::LookupCallable(
+ const QualifiedName& name, const Container& declaration_container,
+ const TypeVector& parameter_types,
+ const std::vector<Binding<LocalLabel>*>& labels,
const TypeVector& specialization_types) {
Callable* result = nullptr;
- TypeVector parameter_types(arguments.parameters.GetTypeVector());
- bool has_template_arguments = !specialization_types.empty();
- std::string mangled_name = name;
- if (has_template_arguments) {
- mangled_name = GetGeneratedCallableName(name, specialization_types);
- }
- Declarable* declarable = declarations()->Lookup(mangled_name);
- if (declarable->IsBuiltin()) {
- result = Builtin::cast(declarable);
- } else if (declarable->IsRuntimeFunction()) {
- result = RuntimeFunction::cast(declarable);
- } else if (declarable->IsMacroList()) {
- std::vector<Macro*> candidates;
- std::vector<Macro*> macros_with_same_name;
- for (Macro* m : MacroList::cast(declarable)->list()) {
- bool try_bool_context =
- arguments.labels.size() == 0 &&
- m->signature().return_type == TypeOracle::GetNeverType();
- Label* true_label = nullptr;
- Label* false_label = nullptr;
- if (try_bool_context) {
- true_label = declarations()->TryLookupLabel(kTrueLabelName);
- false_label = declarations()->TryLookupLabel(kFalseLabelName);
- }
- if (IsCompatibleSignature(m->signature(), parameter_types,
- arguments.labels) ||
- (true_label && false_label &&
- IsCompatibleSignature(m->signature(), parameter_types,
- {true_label, false_label}))) {
- candidates.push_back(m);
- } else {
- macros_with_same_name.push_back(m);
- }
- }
- if (candidates.empty() && macros_with_same_name.empty()) {
- std::stringstream stream;
- stream << "no matching declaration found for " << name;
- ReportError(stream.str());
- } else if (candidates.empty()) {
- FailMacroLookup("cannot find macro with name", name, arguments,
- macros_with_same_name);
- }
-
- auto is_better_candidate = [&](Macro* a, Macro* b) {
- return ParameterDifference(a->signature().parameter_types.types,
- parameter_types)
- .StrictlyBetterThan(ParameterDifference(
- b->signature().parameter_types.types, parameter_types));
- };
-
- Macro* best = *std::min_element(candidates.begin(), candidates.end(),
- is_better_candidate);
- for (Macro* candidate : candidates) {
- if (candidate != best && !is_better_candidate(best, candidate)) {
- FailMacroLookup("ambiguous macro", name, arguments, candidates);
+ std::vector<Declarable*> overloads;
+ std::vector<Signature> overload_signatures;
+ for (auto* declarable : declaration_container) {
+ if (Generic* generic = Generic::DynamicCast(declarable)) {
+ base::Optional<TypeVector> inferred_specialization_types =
+ generic->InferSpecializationTypes(specialization_types,
+ parameter_types);
+ if (!inferred_specialization_types) continue;
+ overloads.push_back(generic);
+ overload_signatures.push_back(
+ DeclarationVisitor().MakeSpecializedSignature(
+ SpecializationKey{generic, *inferred_specialization_types}));
+ } else if (Callable* callable = Callable::DynamicCast(declarable)) {
+ overloads.push_back(callable);
+ overload_signatures.push_back(callable->signature());
+ }
+ }
+ // Indices of candidates in overloads/overload_signatures.
+ std::vector<size_t> candidates;
+ for (size_t i = 0; i < overloads.size(); ++i) {
+ const Signature& signature = overload_signatures[i];
+ bool try_bool_context = labels.size() == 0 &&
+ signature.return_type == TypeOracle::GetNeverType();
+ base::Optional<Binding<LocalLabel>*> true_label;
+ base::Optional<Binding<LocalLabel>*> false_label;
+ if (try_bool_context) {
+ true_label = TryLookupLabel(kTrueLabelName);
+ false_label = TryLookupLabel(kFalseLabelName);
+ }
+ if (IsCompatibleSignature(signature, parameter_types, labels) ||
+ (true_label && false_label &&
+ IsCompatibleSignature(signature, parameter_types,
+ {*true_label, *false_label}))) {
+ candidates.push_back(i);
+ }
+ }
+
+ if (overloads.empty()) {
+ std::stringstream stream;
+ stream << "no matching declaration found for " << name;
+ ReportError(stream.str());
+ } else if (candidates.empty()) {
+ FailCallableLookup("cannot find suitable callable with name", name,
+ parameter_types, labels, overload_signatures);
+ }
+
+ auto is_better_candidate = [&](size_t a, size_t b) {
+ return ParameterDifference(overload_signatures[a].GetExplicitTypes(),
+ parameter_types)
+ .StrictlyBetterThan(ParameterDifference(
+ overload_signatures[b].GetExplicitTypes(), parameter_types));
+ };
+
+ size_t best = *std::min_element(candidates.begin(), candidates.end(),
+ is_better_candidate);
+ // This check is contained in libstdc++'s std::min_element.
+ DCHECK(!is_better_candidate(best, best));
+ for (size_t candidate : candidates) {
+ if (candidate != best && !is_better_candidate(best, candidate)) {
+ std::vector<Signature> candidate_signatures;
+ for (size_t i : candidates) {
+ candidate_signatures.push_back(overload_signatures[i]);
}
+ FailCallableLookup("ambiguous callable ", name, parameter_types, labels,
+ candidate_signatures);
}
- result = best;
+ }
+
+ if (Generic* generic = Generic::DynamicCast(overloads[best])) {
+ result = GetOrCreateSpecialization(
+ SpecializationKey{generic, *generic->InferSpecializationTypes(
+ specialization_types, parameter_types)});
} else {
- std::stringstream stream;
- stream << "can't call " << declarable->type_name() << " " << name
- << " because it's not callable"
- << ": call parameters were (" << parameter_types << ")";
- ReportError(stream.str());
+ result = Callable::cast(overloads[best]);
}
size_t caller_size = parameter_types.size();
- size_t callee_size = result->signature().types().size();
+ size_t callee_size =
+ result->signature().types().size() - result->signature().implicit_count;
if (caller_size != callee_size &&
!result->signature().parameter_types.var_args) {
std::stringstream stream;
@@ -1425,19 +1587,30 @@ Callable* ImplementationVisitor::LookupCall(
ReportError(stream.str());
}
- if (has_template_arguments) {
- Generic* generic = *result->generic();
- CallableNode* callable = generic->declaration()->callable;
- if (generic->declaration()->body) {
- QueueGenericSpecialization({generic, specialization_types}, callable,
- callable->signature.get(),
- generic->declaration()->body);
- }
- }
-
return result;
}
+template <class Container>
+Callable* ImplementationVisitor::LookupCallable(
+ const QualifiedName& name, const Container& declaration_container,
+ const Arguments& arguments, const TypeVector& specialization_types) {
+ return LookupCallable(name, declaration_container,
+ arguments.parameters.GetTypeVector(), arguments.labels,
+ specialization_types);
+}
+
+Method* ImplementationVisitor::LookupMethod(
+ const std::string& name, LocationReference this_reference,
+ const Arguments& arguments, const TypeVector& specialization_types) {
+ TypeVector types(arguments.parameters.GetTypeVector());
+ types.insert(types.begin(), this_reference.GetVisitResult().type());
+ return Method::cast(
+ LookupCallable({{}, name},
+ AggregateType::cast(this_reference.GetVisitResult().type())
+ ->Methods(name),
+ types, arguments.labels, specialization_types));
+}
+
const Type* ImplementationVisitor::GetCommonType(const Type* left,
const Type* right) {
const Type* common_type;
@@ -1461,29 +1634,28 @@ VisitResult ImplementationVisitor::GenerateCopy(const VisitResult& to_copy) {
}
VisitResult ImplementationVisitor::Visit(StructExpression* decl) {
- const Type* raw_type = declarations()->LookupType(decl->name);
+ StackScope stack_scope(this);
+ const Type* raw_type = Declarations::LookupType(
+ QualifiedName(decl->namespace_qualification, decl->name));
if (!raw_type->IsStructType()) {
std::stringstream s;
s << decl->name << " is not a struct but used like one ";
ReportError(s.str());
}
const StructType* struct_type = StructType::cast(raw_type);
- if (struct_type->fields().size() != decl->expressions.size()) {
- std::stringstream s;
- s << "initializer count mismatch for struct " << decl->name << " (expected "
- << struct_type->fields().size() << ", found " << decl->expressions.size()
- << ")";
- ReportError(s.str());
+ // Push unitialized 'this'
+ VisitResult uninitialized_struct = TemporaryUninitializedStruct(
+ struct_type,
+ "it's not set in the constructor for struct " + struct_type->name());
+ Arguments constructor_arguments;
+ for (auto p : decl->expressions) {
+ constructor_arguments.parameters.push_back(Visit(p));
}
- StackRange stack_range = assembler().TopRange(0);
- for (size_t i = 0; i < struct_type->fields().size(); ++i) {
- const NameAndType& field = struct_type->fields()[i];
- StackScope scope(this);
- VisitResult value = Visit(decl->expressions[i]);
- value = GenerateImplicitConvert(field.type, value);
- stack_range.Extend(scope.Yield(value).stack_range());
- }
- return VisitResult(struct_type, stack_range);
+ LocationReference this_ref =
+ LocationReference::VariableAccess(uninitialized_struct);
+ Callable* callable = LookupConstructor(this_ref, constructor_arguments, {});
+ GenerateCall(callable, this_ref, constructor_arguments, {}, false);
+ return stack_scope.Yield(uninitialized_struct);
}
LocationReference ImplementationVisitor::GetLocationReference(
@@ -1528,26 +1700,61 @@ LocationReference ImplementationVisitor::GetLocationReference(
LocationReference ImplementationVisitor::GetLocationReference(
IdentifierExpression* expr) {
- Value* value = declarations()->LookupValue(expr->name);
- if (auto* constant = ModuleConstant::DynamicCast(value)) {
+ if (expr->namespace_qualification.empty()) {
+ if (base::Optional<Binding<LocalValue>*> value =
+ TryLookupLocalValue(expr->name)) {
+ if (expr->generic_arguments.size() != 0) {
+ ReportError("cannot have generic parameters on local name ",
+ expr->name);
+ }
+ if ((*value)->is_const) {
+ return LocationReference::Temporary((*value)->value,
+ "constant value " + expr->name);
+ }
+ return LocationReference::VariableAccess((*value)->value);
+ }
+ }
+
+ if (expr->IsThis()) {
+ ReportError("\"this\" cannot be qualified");
+ }
+ QualifiedName name = QualifiedName(expr->namespace_qualification, expr->name);
+ if (base::Optional<Builtin*> builtin = Declarations::TryLookupBuiltin(name)) {
+ return LocationReference::Temporary(GetBuiltinCode(*builtin),
+ "builtin " + expr->name);
+ }
+ if (expr->generic_arguments.size() != 0) {
+ Generic* generic = Declarations::LookupUniqueGeneric(name);
+ Callable* specialization = GetOrCreateSpecialization(
+ SpecializationKey{generic, GetTypeVector(expr->generic_arguments)});
+ if (Builtin* builtin = Builtin::DynamicCast(specialization)) {
+ DCHECK(!builtin->IsExternal());
+ return LocationReference::Temporary(GetBuiltinCode(builtin),
+ "builtin " + expr->name);
+ } else {
+ ReportError("cannot create function pointer for non-builtin ",
+ generic->name());
+ }
+ }
+ Value* value = Declarations::LookupValue(name);
+ if (auto* constant = NamespaceConstant::DynamicCast(value)) {
if (constant->type()->IsConstexpr()) {
return LocationReference::Temporary(
- VisitResult(constant->type(), constant->constant_name() + "()"),
- "module constant " + expr->name);
+ VisitResult(constant->type(), constant->ExternalAssemblerName() +
+ "(state_)." +
+ constant->constant_name() + "()"),
+ "namespace constant " + expr->name);
}
- assembler().Emit(ModuleConstantInstruction{constant});
+ assembler().Emit(NamespaceConstantInstruction{constant});
StackRange stack_range =
assembler().TopRange(LoweredSlotCount(constant->type()));
return LocationReference::Temporary(
VisitResult(constant->type(), stack_range),
- "module constant " + expr->name);
+ "namespace constant " + expr->name);
}
- if (value->IsConst()) {
- return LocationReference::Temporary(value->value(),
- "constant value " + expr->name);
- }
- DCHECK(value->IsVariable());
- return LocationReference::VariableAccess(value->value());
+ ExternConstant* constant = ExternConstant::cast(value);
+ return LocationReference::Temporary(constant->value(),
+ "extern value " + expr->name);
}
VisitResult ImplementationVisitor::GenerateFetchFromLocation(
@@ -1577,7 +1784,8 @@ void ImplementationVisitor::GenerateAssignToLocation(
variable.type());
} else {
DCHECK(reference.IsTemporary());
- ReportError("cannot assign to ", reference.temporary_description());
+ ReportError("cannot assign to temporary ",
+ reference.temporary_description());
}
}
@@ -1586,14 +1794,14 @@ VisitResult ImplementationVisitor::GeneratePointerCall(
StackScope scope(this);
TypeVector parameter_types(arguments.parameters.GetTypeVector());
VisitResult callee_result = Visit(callee);
- if (!callee_result.type()->IsFunctionPointerType()) {
+ if (!callee_result.type()->IsBuiltinPointerType()) {
std::stringstream stream;
stream << "Expected a function pointer type but found "
<< *callee_result.type();
ReportError(stream.str());
}
- const FunctionPointerType* type =
- FunctionPointerType::cast(callee_result.type());
+ const BuiltinPointerType* type =
+ BuiltinPointerType::cast(callee_result.type());
if (type->parameter_types().size() != parameter_types.size()) {
std::stringstream stream;
@@ -1624,16 +1832,8 @@ VisitResult ImplementationVisitor::GeneratePointerCall(
.stack_range());
}
- Builtin* example_builtin =
- declarations()->FindSomeInternalBuiltinWithType(type);
- if (!example_builtin) {
- std::stringstream stream;
- stream << "unable to find any builtin with type \"" << *type << "\"";
- ReportError(stream.str());
- }
-
- assembler().Emit(CallBuiltinPointerInstruction{is_tailcall, example_builtin,
- arg_range.Size()});
+ assembler().Emit(
+ CallBuiltinPointerInstruction{is_tailcall, type, arg_range.Size()});
if (is_tailcall) {
return VisitResult::NeverResult();
@@ -1642,19 +1842,32 @@ VisitResult ImplementationVisitor::GeneratePointerCall(
return scope.Yield(VisitResult(type->return_type(), assembler().TopRange(1)));
}
-VisitResult ImplementationVisitor::GenerateCall(
- const std::string& callable_name, Arguments arguments,
- const TypeVector& specialization_types, bool is_tailcall) {
- Callable* callable =
- LookupCall(callable_name, arguments, specialization_types);
+void ImplementationVisitor::AddCallParameter(
+ Callable* callable, VisitResult parameter, const Type* parameter_type,
+ std::vector<VisitResult>* converted_arguments, StackRange* argument_range,
+ std::vector<std::string>* constexpr_arguments) {
+ VisitResult converted = GenerateImplicitConvert(parameter_type, parameter);
+ converted_arguments->push_back(converted);
+ if (!callable->ShouldBeInlined()) {
+ if (converted.IsOnStack()) {
+ argument_range->Extend(converted.stack_range());
+ } else {
+ constexpr_arguments->push_back(converted.constexpr_value());
+ }
+ }
+}
+VisitResult ImplementationVisitor::GenerateCall(
+ Callable* callable, base::Optional<LocationReference> this_reference,
+ Arguments arguments, const TypeVector& specialization_types,
+ bool is_tailcall) {
// Operators used in a branching context can also be function calls that never
// return but have a True and False label
if (arguments.labels.size() == 0 &&
callable->signature().labels.size() == 2) {
- Label* true_label = declarations()->LookupLabel(kTrueLabelName);
+ Binding<LocalLabel>* true_label = LookupLabel(kTrueLabelName);
arguments.labels.push_back(true_label);
- Label* false_label = declarations()->LookupLabel(kFalseLabelName);
+ Binding<LocalLabel>* false_label = LookupLabel(kFalseLabelName);
arguments.labels.push_back(false_label);
}
@@ -1663,36 +1876,81 @@ VisitResult ImplementationVisitor::GenerateCall(
std::vector<VisitResult> converted_arguments;
StackRange argument_range = assembler().TopRange(0);
std::vector<std::string> constexpr_arguments;
- for (size_t current = 0; current < arguments.parameters.size(); ++current) {
- const Type* to_type = (current >= callable->signature().types().size())
- ? TypeOracle::GetObjectType()
- : callable->signature().types()[current];
- VisitResult converted =
- GenerateImplicitConvert(to_type, arguments.parameters[current]);
- converted_arguments.push_back(converted);
- if (converted.IsOnStack()) {
- argument_range.Extend(converted.stack_range());
+
+ size_t current = 0;
+ for (; current < callable->signature().implicit_count; ++current) {
+ std::string implicit_name = callable->signature().parameter_names[current];
+ base::Optional<Binding<LocalValue>*> val =
+ TryLookupLocalValue(implicit_name);
+ if (!val) {
+ ReportError("implicit parameter '", implicit_name,
+ "' required for call to '", callable->ReadableName(),
+ "' is not defined");
+ }
+ AddCallParameter(callable, (*val)->value,
+ callable->signature().parameter_types.types[current],
+ &converted_arguments, &argument_range,
+ &constexpr_arguments);
+ }
+
+ if (this_reference) {
+ DCHECK(callable->IsMethod());
+ Method* method = Method::cast(callable);
+ // By now, the this reference should either be a variable or
+ // a temporary, in both cases the fetch of the VisitResult should succeed.
+ VisitResult this_value = this_reference->GetVisitResult();
+ if (method->ShouldBeInlined()) {
+ if (!this_value.type()->IsSubtypeOf(method->aggregate_type())) {
+ ReportError("this parameter must be a subtype of ",
+ *method->aggregate_type(), " but it is of type ",
+ this_value.type());
+ }
} else {
- constexpr_arguments.push_back(converted.constexpr_value());
+ AddCallParameter(callable, this_value, method->aggregate_type(),
+ &converted_arguments, &argument_range,
+ &constexpr_arguments);
}
+ ++current;
+ }
+
+ for (auto arg : arguments.parameters) {
+ const Type* to_type = (current >= callable->signature().types().size())
+ ? TypeOracle::GetObjectType()
+ : callable->signature().types()[current++];
+ AddCallParameter(callable, arg, to_type, &converted_arguments,
+ &argument_range, &constexpr_arguments);
}
- if (global_context_.verbose()) {
- std::cout << "generating code for call to " << callable_name << "\n";
+ if (GlobalContext::verbose()) {
+ std::cout << "generating code for call to " << callable->ReadableName()
+ << "\n";
}
size_t label_count = callable->signature().labels.size();
if (label_count != arguments.labels.size()) {
std::stringstream s;
- s << "unexpected number of otherwise labels for " << callable->name()
- << " (expected " << std::to_string(label_count) << " found "
+ s << "unexpected number of otherwise labels for "
+ << callable->ReadableName() << " (expected "
+ << std::to_string(label_count) << " found "
<< std::to_string(arguments.labels.size()) << ")";
ReportError(s.str());
}
+ if (callable->IsTransitioning()) {
+ if (!CurrentCallable::Get()->IsTransitioning()) {
+ std::stringstream s;
+ s << *CurrentCallable::Get()
+ << " isn't marked transitioning but calls the transitioning "
+ << *callable;
+ ReportError(s.str());
+ }
+ }
+
if (auto* builtin = Builtin::DynamicCast(callable)) {
- assembler().Emit(
- CallBuiltinInstruction{is_tailcall, builtin, argument_range.Size()});
+ base::Optional<Block*> catch_block = GetCatchBlock();
+ assembler().Emit(CallBuiltinInstruction{
+ is_tailcall, builtin, argument_range.Size(), catch_block});
+ GenerateCatchBlock(catch_block);
if (is_tailcall) {
return VisitResult::NeverResult();
} else {
@@ -1709,7 +1967,8 @@ VisitResult ImplementationVisitor::GenerateCall(
if (return_type->IsConstexpr()) {
DCHECK_EQ(0, arguments.labels.size());
std::stringstream result;
- result << "(" << macro->name() << "(";
+ result << "(" << macro->external_assembler_name() << "(state_)."
+ << macro->ExternalName() << "(";
bool first = true;
for (VisitResult arg : arguments.parameters) {
DCHECK(!arg.IsOnStack());
@@ -1721,9 +1980,19 @@ VisitResult ImplementationVisitor::GenerateCall(
}
result << "))";
return VisitResult(return_type, result.str());
+ } else if (macro->ShouldBeInlined()) {
+ std::vector<Block*> label_blocks;
+ for (Binding<LocalLabel>* label : arguments.labels) {
+ label_blocks.push_back(label->block);
+ }
+ return InlineMacro(macro, this_reference, converted_arguments,
+ label_blocks);
} else if (arguments.labels.empty() &&
return_type != TypeOracle::GetNeverType()) {
- assembler().Emit(CallCsaMacroInstruction{macro, constexpr_arguments});
+ base::Optional<Block*> catch_block = GetCatchBlock();
+ assembler().Emit(
+ CallCsaMacroInstruction{macro, constexpr_arguments, catch_block});
+ GenerateCatchBlock(catch_block);
size_t return_slot_count = LoweredSlotCount(return_type);
return VisitResult(return_type, assembler().TopRange(return_slot_count));
} else {
@@ -1737,40 +2006,38 @@ VisitResult ImplementationVisitor::GenerateCall(
for (size_t i = 0; i < label_count; ++i) {
label_blocks.push_back(assembler().NewBlock());
}
-
+ base::Optional<Block*> catch_block = GetCatchBlock();
assembler().Emit(CallCsaMacroAndBranchInstruction{
- macro, constexpr_arguments, return_continuation, label_blocks});
+ macro, constexpr_arguments, return_continuation, label_blocks,
+ catch_block});
+ GenerateCatchBlock(catch_block);
for (size_t i = 0; i < label_count; ++i) {
- Label* label = arguments.labels[i];
+ Binding<LocalLabel>* label = arguments.labels[i];
size_t callee_label_parameters =
callable->signature().labels[i].types.size();
- if (label->GetParameterCount() != callee_label_parameters) {
+ if (label->parameter_types.size() != callee_label_parameters) {
std::stringstream s;
s << "label " << label->name()
<< " doesn't have the right number of parameters (found "
- << std::to_string(label->GetParameterCount()) << " expected "
+ << std::to_string(label->parameter_types.size()) << " expected "
<< std::to_string(callee_label_parameters) << ")";
ReportError(s.str());
}
assembler().Bind(label_blocks[i]);
assembler().Goto(
- label->block(),
+ label->block,
LowerParameterTypes(callable->signature().labels[i].types).size());
size_t j = 0;
for (auto t : callable->signature().labels[i].types) {
- Variable* variable = label->GetParameter(j);
- if (!(variable->type() == t)) {
- std::stringstream s;
- s << "mismatch of label parameters (expected " << *t << " got "
- << *label->GetParameter(j)->type() << " for parameter "
- << std::to_string(i + 1) << ")";
- ReportError(s.str());
+ const Type* parameter_type = label->parameter_types[j];
+ if (parameter_type != t) {
+ ReportError("mismatch of label parameters (expected ", *t, " got ",
+ parameter_type, " for parameter ", i + 1, ")");
}
j++;
}
- label->MarkUsed();
}
if (return_continuation) {
@@ -1783,9 +2050,11 @@ VisitResult ImplementationVisitor::GenerateCall(
}
}
} else if (auto* runtime_function = RuntimeFunction::DynamicCast(callable)) {
- assembler().Emit(CallRuntimeInstruction{is_tailcall, runtime_function,
- argument_range.Size()});
- if (is_tailcall) {
+ base::Optional<Block*> catch_block = GetCatchBlock();
+ assembler().Emit(CallRuntimeInstruction{
+ is_tailcall, runtime_function, argument_range.Size(), catch_block});
+ GenerateCatchBlock(catch_block);
+ if (is_tailcall || return_type == TypeOracle::GetNeverType()) {
return VisitResult::NeverResult();
} else {
size_t slot_count = LoweredSlotCount(return_type);
@@ -1794,113 +2063,204 @@ VisitResult ImplementationVisitor::GenerateCall(
// we should assert slot_count == 1 here.
return VisitResult(return_type, assembler().TopRange(slot_count));
}
+ } else if (auto* intrinsic = Intrinsic::DynamicCast(callable)) {
+ if (intrinsic->ExternalName() == "%RawConstexprCast") {
+ if (intrinsic->signature().parameter_types.types.size() != 1 ||
+ constexpr_arguments.size() != 1) {
+ ReportError(
+ "%RawConstexprCast must take a single parameter with constexpr "
+ "type");
+ }
+ if (!return_type->IsConstexpr()) {
+ std::stringstream s;
+ s << *return_type
+ << " return type for %RawConstexprCast is not constexpr";
+ ReportError(s.str());
+ }
+ std::stringstream result;
+ result << "static_cast<" << return_type->GetGeneratedTypeName() << ">(";
+ result << constexpr_arguments[0];
+ result << ")";
+ return VisitResult(return_type, result.str());
+ } else {
+ assembler().Emit(
+ CallIntrinsicInstruction{intrinsic, constexpr_arguments});
+ size_t return_slot_count =
+ LoweredSlotCount(intrinsic->signature().return_type);
+ return VisitResult(return_type, assembler().TopRange(return_slot_count));
+ }
} else {
UNREACHABLE();
}
}
-void ImplementationVisitor::Visit(StandardDeclaration* decl) {
- Signature signature = MakeSignature(decl->callable->signature.get());
- Visit(decl->callable, signature, decl->body);
-}
-
-void ImplementationVisitor::Visit(SpecializationDeclaration* decl) {
- Signature signature_with_types = MakeSignature(decl->signature.get());
- Declarations::NodeScopeActivator specialization_activator(declarations(),
- decl);
- GenericList* generic_list = declarations()->LookupGeneric(decl->name);
- for (Generic* generic : generic_list->list()) {
- CallableNode* callable = generic->declaration()->callable;
- Signature generic_signature_with_types =
- MakeSignature(callable->signature.get());
- if (signature_with_types.HasSameTypesAs(generic_signature_with_types)) {
- TypeVector specialization_types = GetTypeVector(decl->generic_parameters);
- SpecializeGeneric({{generic, specialization_types},
- callable,
- decl->signature.get(),
- decl->body,
- decl->pos});
- return;
- }
- }
- // Because the DeclarationVisitor already performed the same lookup
- // as above to find aspecialization match and already threw if it didn't
- // find one, failure to find a match here should never happen.
- // TODO(danno): Remember the specialization found in the declaration visitor
- // so that the lookup doesn't have to be repeated here.
- UNREACHABLE();
+VisitResult ImplementationVisitor::GenerateCall(
+ const QualifiedName& callable_name, Arguments arguments,
+ const TypeVector& specialization_types, bool is_tailcall) {
+ Callable* callable =
+ LookupCallable(callable_name, Declarations::Lookup(callable_name),
+ arguments, specialization_types);
+ return GenerateCall(callable, base::nullopt, arguments, specialization_types,
+ is_tailcall);
}
VisitResult ImplementationVisitor::Visit(CallExpression* expr,
bool is_tailcall) {
StackScope scope(this);
Arguments arguments;
- std::string name = expr->callee.name;
+ QualifiedName name =
+ QualifiedName(expr->callee->namespace_qualification, expr->callee->name);
TypeVector specialization_types =
- GetTypeVector(expr->callee.generic_arguments);
+ GetTypeVector(expr->callee->generic_arguments);
bool has_template_arguments = !specialization_types.empty();
for (Expression* arg : expr->arguments)
arguments.parameters.push_back(Visit(arg));
arguments.labels = LabelsFromIdentifiers(expr->labels);
- VisitResult result;
- if (!has_template_arguments &&
- declarations()->Lookup(expr->callee.name)->IsValue()) {
+ if (!has_template_arguments && name.namespace_qualification.empty() &&
+ TryLookupLocalValue(name.name)) {
return scope.Yield(
- GeneratePointerCall(&expr->callee, arguments, is_tailcall));
+ GeneratePointerCall(expr->callee, arguments, is_tailcall));
} else {
return scope.Yield(
GenerateCall(name, arguments, specialization_types, is_tailcall));
}
}
-bool ImplementationVisitor::GenerateLabeledStatementBlocks(
- const std::vector<Statement*>& blocks,
- const std::vector<Label*>& statement_labels, Block* merge_block) {
- bool live = false;
- auto label_iterator = statement_labels.begin();
- for (Statement* block : blocks) {
- GenerateLabelBind(*label_iterator++);
- const Type* stmt_result;
- {
- StackScope stack_scope(this);
- stmt_result = Visit(block);
- }
- if (stmt_result != TypeOracle::GetNeverType()) {
- assembler().Goto(merge_block);
- live = true;
+VisitResult ImplementationVisitor::Visit(CallMethodExpression* expr) {
+ StackScope scope(this);
+ Arguments arguments;
+ std::string method_name = expr->method->name;
+ TypeVector specialization_types =
+ GetTypeVector(expr->method->generic_arguments);
+ LocationReference target = GetLocationReference(expr->target);
+ if (!target.IsVariableAccess()) {
+ VisitResult result = GenerateFetchFromLocation(target);
+ target = LocationReference::Temporary(result, "method target result");
+ }
+ const AggregateType* target_type =
+ AggregateType::DynamicCast(target.GetVisitResult().type());
+ if (!target_type) {
+ ReportError("target of method call not a struct or class type");
+ }
+ if (method_name == kConstructMethodName || method_name == kSuperMethodName) {
+ if (CurrentConstructorInfo::Get()) {
+ ConstructorInfo& info = *CurrentConstructorInfo::Get();
+ if (method_name == kSuperMethodName) {
+ if (info.super_calls != 0) {
+ ReportError("\"super\" can only be called once from a constructor");
+ }
+ ++info.super_calls;
+ DCHECK(target_type->IsStructType());
+ base::Optional<const ClassType*> derived_from =
+ StructType::cast(target_type)->GetDerivedFrom();
+ if (!derived_from) {
+ ReportError("\"super\" can only be called from class constructors");
+ }
+ if ((*derived_from)->GetSuperClass() == nullptr) {
+ ReportError(
+ "\"super\" can only be called in constructors for derived "
+ "classes");
+ }
+ } else {
+ ReportError("cannot call a constructor from a constructor");
+ }
+ } else {
+ ReportError(
+ "cannot call a constructor or \"super\" from a non-constructor");
}
}
- return live;
+ for (Expression* arg : expr->arguments) {
+ arguments.parameters.push_back(Visit(arg));
+ }
+ arguments.labels = LabelsFromIdentifiers(expr->labels);
+ TypeVector argument_types = arguments.parameters.GetTypeVector();
+ DCHECK_EQ(expr->method->namespace_qualification.size(), 0);
+ QualifiedName qualified_name = QualifiedName(method_name);
+ Callable* callable = nullptr;
+ if (method_name == kConstructMethodName) {
+ callable = LookupConstructor(target, arguments, {});
+ } else if (method_name == kSuperMethodName) {
+ LocationReference super_this =
+ LocationReference::VariableAccess(ProjectStructField(
+ target.GetVisitResult(), kConstructorStructSuperFieldName));
+ callable = LookupConstructor(super_this, arguments, {});
+ VisitResult super_result =
+ GenerateCall(callable, super_this, arguments, {}, false);
+ return scope.Yield(super_result);
+ } else {
+ callable = LookupMethod(method_name, target, arguments, {});
+ }
+ return scope.Yield(GenerateCall(callable, target, arguments, {}, false));
}
-void ImplementationVisitor::GenerateBranch(const VisitResult& condition,
- Label* true_label,
- Label* false_label) {
- DCHECK_EQ(condition,
- VisitResult(TypeOracle::GetBoolType(), assembler().TopRange(1)));
- assembler().Branch(true_label->block(), false_label->block());
+VisitResult ImplementationVisitor::Visit(LoadObjectFieldExpression* expr) {
+ VisitResult base_result = Visit(expr->base);
+ auto class_type = ClassType::DynamicCast(base_result.type());
+ if (!class_type) {
+ ReportError(
+ "base expression for a LoadObjectFieldExpression is not a class type "
+ "but instead ",
+ *base_result.type());
+ }
+ VisitResult result = base_result;
+ assembler().Emit(LoadObjectFieldInstruction{class_type, expr->field_name});
+ const Field& field = class_type->LookupField(expr->field_name);
+ result.SetType(field.name_and_type.type);
+ return result;
+}
+
+VisitResult ImplementationVisitor::Visit(StoreObjectFieldExpression* expr) {
+ VisitResult base_result = Visit(expr->base);
+ auto class_type = ClassType::DynamicCast(base_result.type());
+ if (!class_type) {
+ ReportError(
+ "base expression for a StoreObjectFieldExpression is not a class type "
+ "but instead ",
+ *base_result.type());
+ }
+ VisitResult value = Visit(expr->value);
+ assembler().Emit(StoreObjectFieldInstruction{class_type, expr->field_name});
+ return VisitResult(value.type(), assembler().TopRange(0));
}
-bool ImplementationVisitor::GenerateExpressionBranch(
- Expression* expression, const std::vector<Label*>& statement_labels,
- const std::vector<Statement*>& statement_blocks, Block* merge_block) {
- // Activate a new scope to define True/False catch labels
- Declarations::NodeScopeActivator scope(declarations(), expression);
+VisitResult ImplementationVisitor::Visit(IntrinsicCallExpression* expr) {
+ StackScope scope(this);
+ Arguments arguments;
+ TypeVector specialization_types = GetTypeVector(expr->generic_arguments);
+ for (Expression* arg : expr->arguments)
+ arguments.parameters.push_back(Visit(arg));
+ return scope.Yield(
+ GenerateCall(expr->name, arguments, specialization_types, false));
+}
+void ImplementationVisitor::GenerateBranch(const VisitResult& condition,
+ Block* true_block,
+ Block* false_block) {
+ DCHECK_EQ(condition,
+ VisitResult(TypeOracle::GetBoolType(), assembler().TopRange(1)));
+ assembler().Branch(true_block, false_block);
+}
+
+void ImplementationVisitor::GenerateExpressionBranch(Expression* expression,
+ Block* true_block,
+ Block* false_block) {
+ // Conditional expressions can either explicitly return a bit
+ // type, or they can be backed by macros that don't return but
+ // take a true and false label. By declaring the labels before
+ // visiting the conditional expression, those label-based
+ // macro conditionals will be able to find them through normal
+ // label lookups.
+ Binding<LocalLabel> true_binding{&LabelBindingsManager::Get(), kTrueLabelName,
+ LocalLabel{true_block}};
+ Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
+ kFalseLabelName, LocalLabel{false_block}};
+ StackScope stack_scope(this);
VisitResult expression_result = Visit(expression);
- if (expression_result.type() == TypeOracle::GetBoolType()) {
- GenerateBranch(expression_result, statement_labels[0], statement_labels[1]);
- } else {
- if (expression_result.type() != TypeOracle::GetNeverType()) {
- std::stringstream s;
- s << "unexpected return type " << *expression_result.type()
- << " for branch expression";
- ReportError(s.str());
- }
+ if (!expression_result.type()->IsNever()) {
+ expression_result = stack_scope.Yield(
+ GenerateImplicitConvert(TypeOracle::GetBoolType(), expression_result));
+ GenerateBranch(expression_result, true_block, false_block);
}
-
- return GenerateLabeledStatementBlocks(statement_blocks, statement_labels,
- merge_block);
}
VisitResult ImplementationVisitor::GenerateImplicitConvert(
@@ -1916,9 +2276,8 @@ VisitResult ImplementationVisitor::GenerateImplicitConvert(
if (TypeOracle::IsImplicitlyConvertableFrom(destination_type,
source.type())) {
- std::string name =
- GetGeneratedCallableName(kFromConstexprMacroName, {destination_type});
- return scope.Yield(GenerateCall(name, {{source}, {}}, {}, false));
+ return scope.Yield(GenerateCall(kFromConstexprMacroName, {{source}, {}},
+ {destination_type, source.type()}, false));
} else if (IsAssignableFrom(destination_type, source.type())) {
source.SetType(destination_type);
return scope.Yield(GenerateCopy(source));
@@ -1930,26 +2289,17 @@ VisitResult ImplementationVisitor::GenerateImplicitConvert(
}
}
-void ImplementationVisitor::CreateBlockForLabel(Label* label,
- Stack<const Type*> stack) {
- label->set_block(assembler().NewBlock(std::move(stack), label->IsDeferred()));
-}
-
-void ImplementationVisitor::GenerateLabelBind(Label* label) {
- assembler().Bind(label->block());
-}
-
StackRange ImplementationVisitor::GenerateLabelGoto(
- Label* label, base::Optional<StackRange> arguments) {
- return assembler().Goto(label->block(), arguments ? arguments->Size() : 0);
+ LocalLabel* label, base::Optional<StackRange> arguments) {
+ return assembler().Goto(label->block, arguments ? arguments->Size() : 0);
}
-std::vector<Label*> ImplementationVisitor::LabelsFromIdentifiers(
+std::vector<Binding<LocalLabel>*> ImplementationVisitor::LabelsFromIdentifiers(
const std::vector<std::string>& names) {
- std::vector<Label*> result;
+ std::vector<Binding<LocalLabel>*> result;
result.reserve(names.size());
for (const auto& name : names) {
- result.push_back(declarations()->LookupLabel(name));
+ result.push_back(LookupLabel(name));
}
return result;
}
@@ -1957,12 +2307,12 @@ std::vector<Label*> ImplementationVisitor::LabelsFromIdentifiers(
StackRange ImplementationVisitor::LowerParameter(
const Type* type, const std::string& parameter_name,
Stack<std::string>* lowered_parameters) {
- if (type->IsStructType()) {
- const StructType* struct_type = StructType::cast(type);
+ if (const StructType* struct_type = StructType::DynamicCast(type)) {
StackRange range = lowered_parameters->TopRange(0);
for (auto& field : struct_type->fields()) {
StackRange parameter_range = LowerParameter(
- field.type, parameter_name + "." + field.name, lowered_parameters);
+ field.name_and_type.type,
+ parameter_name + "." + field.name_and_type.name, lowered_parameters);
range.Extend(parameter_range);
}
return range;
@@ -1972,9 +2322,215 @@ StackRange ImplementationVisitor::LowerParameter(
}
}
-std::string ImplementationVisitor::ExternalLabelParameterName(Label* label,
- size_t i) {
- return label->external_label_name() + "_parameter_" + std::to_string(i);
+std::string ImplementationVisitor::ExternalLabelName(
+ const std::string& label_name) {
+ return "label_" + label_name;
+}
+
+std::string ImplementationVisitor::ExternalLabelParameterName(
+ const std::string& label_name, size_t i) {
+ return "label_" + label_name + "_parameter_" + std::to_string(i);
+}
+
+std::string ImplementationVisitor::ExternalParameterName(
+ const std::string& name) {
+ return std::string("p_") + name;
+}
+
+DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::ValueBindingsManager);
+DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::LabelBindingsManager);
+DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentCallable);
+DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentReturnValue);
+DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentConstructorInfo);
+
+bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
+ const std::vector<Binding<LocalLabel>*>& labels) {
+ auto i = sig.parameter_types.types.begin() + sig.implicit_count;
+ if ((sig.parameter_types.types.size() - sig.implicit_count) > types.size())
+ return false;
+ // TODO(danno): The test below is actually insufficient. The labels'
+ // parameters must be checked too. ideally, the named part of
+ // LabelDeclarationVector would be factored out so that the label count and
+ // parameter types could be passed separately.
+ if (sig.labels.size() != labels.size()) return false;
+ for (auto current : types) {
+ if (i == sig.parameter_types.types.end()) {
+ if (!sig.parameter_types.var_args) return false;
+ if (!IsAssignableFrom(TypeOracle::GetObjectType(), current)) return false;
+ } else {
+ if (!IsAssignableFrom(*i++, current)) return false;
+ }
+ }
+ return true;
+}
+
+base::Optional<Block*> ImplementationVisitor::GetCatchBlock() {
+ base::Optional<Block*> catch_block;
+ if (base::Optional<Binding<LocalLabel>*> catch_handler =
+ TryLookupLabel("_catch")) {
+ catch_block = assembler().NewBlock(base::nullopt, true);
+ }
+ return catch_block;
+}
+
+void ImplementationVisitor::GenerateCatchBlock(
+ base::Optional<Block*> catch_block) {
+ if (catch_block) {
+ base::Optional<Binding<LocalLabel>*> catch_handler =
+ TryLookupLabel("_catch");
+ if (assembler().CurrentBlockIsComplete()) {
+ assembler().Bind(*catch_block);
+ assembler().Goto((*catch_handler)->block, 1);
+ } else {
+ CfgAssemblerScopedTemporaryBlock temp(&assembler(), *catch_block);
+ assembler().Goto((*catch_handler)->block, 1);
+ }
+ }
+}
+
+void ImplementationVisitor::VisitAllDeclarables() {
+ const std::vector<std::unique_ptr<Declarable>>& all_declarables =
+ GlobalContext::AllDeclarables();
+ // This has to be an index-based loop because all_declarables can be extended
+ // during the loop.
+ for (size_t i = 0; i < all_declarables.size(); ++i) {
+ Visit(all_declarables[i].get());
+ }
+}
+
+void ImplementationVisitor::Visit(Declarable* declarable) {
+ CurrentConstructorInfo::Scope current_constructor(base::nullopt);
+ CurrentScope::Scope current_scope(declarable->ParentScope());
+ CurrentSourcePosition::Scope current_source_position(declarable->pos());
+ switch (declarable->kind()) {
+ case Declarable::kMacro:
+ return Visit(Macro::cast(declarable));
+ case Declarable::kMethod:
+ return Visit(Method::cast(declarable));
+ case Declarable::kBuiltin:
+ return Visit(Builtin::cast(declarable));
+ case Declarable::kTypeAlias:
+ return Visit(TypeAlias::cast(declarable));
+ case Declarable::kNamespaceConstant:
+ return Visit(NamespaceConstant::cast(declarable));
+ case Declarable::kRuntimeFunction:
+ case Declarable::kIntrinsic:
+ case Declarable::kExternConstant:
+ case Declarable::kNamespace:
+ case Declarable::kGeneric:
+ return;
+ }
+}
+
+void ImplementationVisitor::GenerateBuiltinDefinitions(std::string& file_name) {
+ std::stringstream new_contents_stream;
+ new_contents_stream
+ << "#ifndef V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
+ "#define V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
+ "\n"
+ "#define BUILTIN_LIST_FROM_DSL(CPP, API, TFJ, TFC, TFS, TFH, ASM) "
+ "\\\n";
+ for (auto& declarable : GlobalContext::AllDeclarables()) {
+ Builtin* builtin = Builtin::DynamicCast(declarable.get());
+ if (!builtin || builtin->IsExternal()) continue;
+ int firstParameterIndex = 1;
+ bool declareParameters = true;
+ if (builtin->IsStub()) {
+ new_contents_stream << "TFS(" << builtin->ExternalName();
+ } else {
+ new_contents_stream << "TFJ(" << builtin->ExternalName();
+ if (builtin->IsVarArgsJavaScript()) {
+ new_contents_stream
+ << ", SharedFunctionInfo::kDontAdaptArgumentsSentinel";
+ declareParameters = false;
+ } else {
+ assert(builtin->IsFixedArgsJavaScript());
+ // FixedArg javascript builtins need to offer the parameter
+ // count.
+ assert(builtin->parameter_names().size() >= 2);
+ new_contents_stream << ", " << (builtin->parameter_names().size() - 2);
+ // And the receiver is explicitly declared.
+ new_contents_stream << ", kReceiver";
+ firstParameterIndex = 2;
+ }
+ }
+ if (declareParameters) {
+ int index = 0;
+ for (const auto& parameter : builtin->parameter_names()) {
+ if (index >= firstParameterIndex) {
+ new_contents_stream << ", k" << CamelifyString(parameter);
+ }
+ index++;
+ }
+ }
+ new_contents_stream << ") \\\n";
+ }
+ new_contents_stream << "\n";
+
+ new_contents_stream
+ << "#define TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(V) \\\n";
+ for (const BuiltinPointerType* type : TypeOracle::AllBuiltinPointerTypes()) {
+ Builtin* example_builtin =
+ Declarations::FindSomeInternalBuiltinWithType(type);
+ if (!example_builtin) {
+ CurrentSourcePosition::Scope current_source_position(
+ SourcePosition{CurrentSourceFile::Get(), -1, -1});
+ ReportError("unable to find any builtin with type \"", *type, "\"");
+ }
+ new_contents_stream << " V(" << type->function_pointer_type_id() << ","
+ << example_builtin->ExternalName() << ")\\\n";
+ }
+ new_contents_stream << "\n";
+
+ new_contents_stream
+ << "#endif // V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";
+
+ std::string new_contents(new_contents_stream.str());
+ ReplaceFileContentsIfDifferent(file_name, new_contents);
+}
+
+void ImplementationVisitor::GenerateClassDefinitions(std::string& file_name) {
+ std::stringstream new_contents_stream;
+ new_contents_stream << "#ifndef V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
+ "#define V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
+ "\n\n";
+
+ for (auto i : GlobalContext::GetClasses()) {
+ // TODO(danno): Ideally (and we've got several core V8 dev's feedback
+ // supporting this), Torque should generate the constants for the offsets
+ // directly and not go through the existing layer of macros, which actually
+ // currently just serves to additionally obfuscate where these values come
+ // from.
+ new_contents_stream << "#define ";
+ new_contents_stream << CapifyStringWithUnderscores(i.first)
+ << "_FIELDS(V) \\\n";
+ const ClassType* type = i.second;
+ std::vector<Field> fields = type->fields();
+ new_contents_stream << "V(kStartOfStrongFieldsOffset, 0) \\\n";
+ for (auto f : fields) {
+ if (!f.is_weak) {
+ new_contents_stream << "V(k" << CamelifyString(f.name_and_type.name)
+ << "Offset, kTaggedSize) \\\n";
+ }
+ }
+ new_contents_stream << "V(kEndOfStrongFieldsOffset, 0) \\\n";
+ new_contents_stream << "V(kStartOfWeakFieldsOffset, 0) \\\n";
+ for (auto f : fields) {
+ if (f.is_weak) {
+ new_contents_stream << "V(k" << CamelifyString(f.name_and_type.name)
+ << "Offset, kTaggedSize) \\\n";
+ }
+ }
+ new_contents_stream << "V(kEndOfWeakFieldsOffset, 0) \\\n";
+ new_contents_stream << "V(kSize, 0) \\\n";
+ new_contents_stream << "\n";
+ }
+
+ new_contents_stream
+ << "\n#endif // V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";
+
+ std::string new_contents(new_contents_stream.str());
+ ReplaceFileContentsIfDifferent(file_name, new_contents);
}
} // namespace torque