Commit 0f15ed05 authored by Daniel Clifford's avatar Daniel Clifford Committed by Commit Bot

[torque]: Implement catch handlers for try blocks

In addition (and in combination), try statements now support "catch"
clauses at the end that catch JavaScript exceptions throw by any builtin
or runtime function contained in the try block:

  try {
    ThrowTypeError(context, ...);
  }
  catch (e) {
    // e has type Object
  }

Bug: v8:7793
Change-Id: Ie285ff888c49c112276240f7360f70c8b540ed19
Reviewed-on: https://chromium-review.googlesource.com/c/1302055
Commit-Queue: Daniel Clifford <danno@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57169}
parent 6627bdb1
...@@ -1083,6 +1083,8 @@ void CodeAssembler::GotoIfException(Node* node, Label* if_exception, ...@@ -1083,6 +1083,8 @@ void CodeAssembler::GotoIfException(Node* node, Label* if_exception,
return; return;
} }
// No catch handlers should be active if we're using catch labels
DCHECK_EQ(state()->exception_handler_labels_.size(), 0);
DCHECK(!node->op()->HasProperty(Operator::kNoThrow)); DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
Label success(this), exception(this, Label::kDeferred); Label success(this), exception(this, Label::kDeferred);
...@@ -1102,6 +1104,29 @@ void CodeAssembler::GotoIfException(Node* node, Label* if_exception, ...@@ -1102,6 +1104,29 @@ void CodeAssembler::GotoIfException(Node* node, Label* if_exception,
Bind(&success); Bind(&success);
} }
void CodeAssembler::HandleException(Node* node) {
if (state_->exception_handler_labels_.size() == 0) return;
CodeAssemblerExceptionHandlerLabel* label =
state_->exception_handler_labels_.back();
if (node->op()->HasProperty(Operator::kNoThrow)) {
return;
}
Label success(this), exception(this, Label::kDeferred);
success.MergeVariables();
exception.MergeVariables();
raw_assembler()->Continuations(node, success.label_, exception.label_);
Bind(&exception);
const Operator* op = raw_assembler()->common()->IfException();
Node* exception_value = raw_assembler()->AddNode(op, node, node);
label->AddInputs({UncheckedCast<Object>(exception_value)});
Goto(label->plain_label());
Bind(&success);
}
namespace { namespace {
template <size_t kMaxSize> template <size_t kMaxSize>
class NodeArray { class NodeArray {
...@@ -1152,6 +1177,7 @@ TNode<Object> CodeAssembler::CallRuntimeWithCEntryImpl( ...@@ -1152,6 +1177,7 @@ TNode<Object> CodeAssembler::CallRuntimeWithCEntryImpl(
CallPrologue(); CallPrologue();
Node* return_value = Node* return_value =
raw_assembler()->CallN(call_descriptor, inputs.size(), inputs.data()); raw_assembler()->CallN(call_descriptor, inputs.size(), inputs.data());
HandleException(return_value);
CallEpilogue(); CallEpilogue();
return UncheckedCast<Object>(return_value); return UncheckedCast<Object>(return_value);
} }
...@@ -1207,6 +1233,7 @@ Node* CodeAssembler::CallStubN(const CallInterfaceDescriptor& descriptor, ...@@ -1207,6 +1233,7 @@ Node* CodeAssembler::CallStubN(const CallInterfaceDescriptor& descriptor,
CallPrologue(); CallPrologue();
Node* return_value = Node* return_value =
raw_assembler()->CallN(call_descriptor, input_count, inputs); raw_assembler()->CallN(call_descriptor, input_count, inputs);
HandleException(return_value);
CallEpilogue(); CallEpilogue();
return return_value; return return_value;
} }
...@@ -1503,6 +1530,10 @@ Factory* CodeAssembler::factory() const { return isolate()->factory(); } ...@@ -1503,6 +1530,10 @@ Factory* CodeAssembler::factory() const { return isolate()->factory(); }
Zone* CodeAssembler::zone() const { return raw_assembler()->zone(); } Zone* CodeAssembler::zone() const { return raw_assembler()->zone(); }
bool CodeAssembler::IsExceptionHandlerActive() const {
return state_->exception_handler_labels_.size() != 0;
}
RawMachineAssembler* CodeAssembler::raw_assembler() const { RawMachineAssembler* CodeAssembler::raw_assembler() const {
return state_->raw_assembler_.get(); return state_->raw_assembler_.get();
} }
...@@ -1810,6 +1841,15 @@ const std::vector<Node*>& CodeAssemblerParameterizedLabelBase::CreatePhis( ...@@ -1810,6 +1841,15 @@ const std::vector<Node*>& CodeAssemblerParameterizedLabelBase::CreatePhis(
return phi_nodes_; return phi_nodes_;
} }
void CodeAssemblerState::PushExceptionHandler(
CodeAssemblerExceptionHandlerLabel* label) {
exception_handler_labels_.push_back(label);
}
void CodeAssemblerState::PopExceptionHandler() {
exception_handler_labels_.pop_back();
}
} // namespace compiler } // namespace compiler
Smi* CheckObjectType(Object* value, Smi* type, String* location) { Smi* CheckObjectType(Object* value, Smi* type, String* location) {
......
...@@ -451,6 +451,9 @@ class SloppyTNode : public TNode<T> { ...@@ -451,6 +451,9 @@ class SloppyTNode : public TNode<T> {
: TNode<T>(other) {} : TNode<T>(other) {}
}; };
template <class... Types>
class CodeAssemblerParameterizedLabel;
// This macro alias allows to use PairT<T1, T2> as a macro argument. // This macro alias allows to use PairT<T1, T2> as a macro argument.
#define PAIR_TYPE(T1, T2) PairT<T1, T2> #define PAIR_TYPE(T1, T2) PairT<T1, T2>
...@@ -807,6 +810,15 @@ class V8_EXPORT_PRIVATE CodeAssembler { ...@@ -807,6 +810,15 @@ class V8_EXPORT_PRIVATE CodeAssembler {
void Branch(SloppyTNode<IntegralT> condition, Label* true_label, void Branch(SloppyTNode<IntegralT> condition, Label* true_label,
Label* false_label); Label* false_label);
template <class... Ts>
using PLabel = compiler::CodeAssemblerParameterizedLabel<Ts...>;
template <class... T, class... Args>
void Goto(PLabel<T...>* label, Args... args) {
label->AddInputs(args...);
Goto(label->plain_label());
}
void Branch(TNode<BoolT> condition, const std::function<void()>& true_body, void Branch(TNode<BoolT> condition, const std::function<void()>& true_body,
const std::function<void()>& false_body); const std::function<void()>& false_body);
void Branch(TNode<BoolT> condition, Label* true_label, void Branch(TNode<BoolT> condition, Label* true_label,
...@@ -1269,6 +1281,8 @@ class V8_EXPORT_PRIVATE CodeAssembler { ...@@ -1269,6 +1281,8 @@ class V8_EXPORT_PRIVATE CodeAssembler {
bool UnalignedLoadSupported(MachineRepresentation rep) const; bool UnalignedLoadSupported(MachineRepresentation rep) const;
bool UnalignedStoreSupported(MachineRepresentation rep) const; bool UnalignedStoreSupported(MachineRepresentation rep) const;
bool IsExceptionHandlerActive() const;
protected: protected:
void RegisterCallGenerationCallbacks( void RegisterCallGenerationCallbacks(
const CodeAssemblerCallback& call_prologue, const CodeAssemblerCallback& call_prologue,
...@@ -1281,6 +1295,8 @@ class V8_EXPORT_PRIVATE CodeAssembler { ...@@ -1281,6 +1295,8 @@ class V8_EXPORT_PRIVATE CodeAssembler {
bool IsJSFunctionCall() const; bool IsJSFunctionCall() const;
private: private:
void HandleException(Node* result);
TNode<Object> CallRuntimeImpl(Runtime::FunctionId function, TNode<Object> CallRuntimeImpl(Runtime::FunctionId function,
TNode<Object> context, TNode<Object> context,
std::initializer_list<TNode<Object>> args); std::initializer_list<TNode<Object>> args);
...@@ -1482,6 +1498,7 @@ class CodeAssemblerParameterizedLabel ...@@ -1482,6 +1498,7 @@ class CodeAssemblerParameterizedLabel
private: private:
friend class internal::TorqueAssembler; friend class internal::TorqueAssembler;
friend class CodeAssembler;
void AddInputs(TNode<Types>... inputs) { void AddInputs(TNode<Types>... inputs) {
CodeAssemblerParameterizedLabelBase::AddInputs( CodeAssemblerParameterizedLabelBase::AddInputs(
...@@ -1501,6 +1518,9 @@ class CodeAssemblerParameterizedLabel ...@@ -1501,6 +1518,9 @@ class CodeAssemblerParameterizedLabel
} }
}; };
typedef CodeAssemblerParameterizedLabel<Object>
CodeAssemblerExceptionHandlerLabel;
class V8_EXPORT_PRIVATE CodeAssemblerState { class V8_EXPORT_PRIVATE CodeAssemblerState {
public: public:
// Create with CallStub linkage. // Create with CallStub linkage.
...@@ -1535,12 +1555,16 @@ class V8_EXPORT_PRIVATE CodeAssemblerState { ...@@ -1535,12 +1555,16 @@ class V8_EXPORT_PRIVATE CodeAssemblerState {
friend class CodeAssemblerVariable; friend class CodeAssemblerVariable;
friend class CodeAssemblerTester; friend class CodeAssemblerTester;
friend class CodeAssemblerParameterizedLabelBase; friend class CodeAssemblerParameterizedLabelBase;
friend class CodeAssemblerScopedExceptionHandler;
CodeAssemblerState(Isolate* isolate, Zone* zone, CodeAssemblerState(Isolate* isolate, Zone* zone,
CallDescriptor* call_descriptor, Code::Kind kind, CallDescriptor* call_descriptor, Code::Kind kind,
const char* name, PoisoningMitigationLevel poisoning_level, const char* name, PoisoningMitigationLevel poisoning_level,
uint32_t stub_key, int32_t builtin_index); uint32_t stub_key, int32_t builtin_index);
void PushExceptionHandler(CodeAssemblerExceptionHandlerLabel* label);
void PopExceptionHandler();
std::unique_ptr<RawMachineAssembler> raw_assembler_; std::unique_ptr<RawMachineAssembler> raw_assembler_;
Code::Kind kind_; Code::Kind kind_;
const char* name_; const char* name_;
...@@ -1550,10 +1574,27 @@ class V8_EXPORT_PRIVATE CodeAssemblerState { ...@@ -1550,10 +1574,27 @@ class V8_EXPORT_PRIVATE CodeAssemblerState {
ZoneSet<CodeAssemblerVariable::Impl*> variables_; ZoneSet<CodeAssemblerVariable::Impl*> variables_;
CodeAssemblerCallback call_prologue_; CodeAssemblerCallback call_prologue_;
CodeAssemblerCallback call_epilogue_; CodeAssemblerCallback call_epilogue_;
std::vector<CodeAssemblerExceptionHandlerLabel*> exception_handler_labels_;
DISALLOW_COPY_AND_ASSIGN(CodeAssemblerState); DISALLOW_COPY_AND_ASSIGN(CodeAssemblerState);
}; };
class CodeAssemblerScopedExceptionHandler {
public:
CodeAssemblerScopedExceptionHandler(CodeAssembler* assembler,
CodeAssemblerExceptionHandlerLabel* label)
: assembler_(assembler) {
assembler_->state()->PushExceptionHandler(label);
}
~CodeAssemblerScopedExceptionHandler() {
assembler_->state()->PopExceptionHandler();
}
private:
CodeAssembler* assembler_;
};
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -28,12 +28,6 @@ class TorqueAssembler : public CodeStubAssembler { ...@@ -28,12 +28,6 @@ class TorqueAssembler : public CodeStubAssembler {
return {}; return {};
} }
template <class... T, class... Args>
void Goto(PLabel<T...>* label, Args... args) {
label->AddInputs(args...);
CodeStubAssembler::Goto(label->plain_label());
}
using CodeStubAssembler::Goto;
template <class... T> template <class... T>
void Bind(PLabel<T...>* label, TNode<T>*... phis) { void Bind(PLabel<T...>* label, TNode<T>*... phis) {
Bind(label->plain_label()); Bind(label->plain_label());
......
...@@ -552,7 +552,7 @@ struct ForOfLoopStatement : Statement { ...@@ -552,7 +552,7 @@ struct ForOfLoopStatement : Statement {
struct LabelBlock : AstNode { struct LabelBlock : AstNode {
DEFINE_AST_NODE_LEAF_BOILERPLATE(LabelBlock) DEFINE_AST_NODE_LEAF_BOILERPLATE(LabelBlock)
LabelBlock(SourcePosition pos, const std::string& label, LabelBlock(SourcePosition pos, std::string label,
const ParameterList& parameters, Statement* body) const ParameterList& parameters, Statement* body)
: AstNode(kKind, pos), : AstNode(kKind, pos),
label(std::move(label)), label(std::move(label)),
...@@ -572,11 +572,13 @@ struct StatementExpression : Expression { ...@@ -572,11 +572,13 @@ struct StatementExpression : Expression {
struct TryLabelExpression : Expression { struct TryLabelExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(TryLabelExpression) DEFINE_AST_NODE_LEAF_BOILERPLATE(TryLabelExpression)
TryLabelExpression(SourcePosition pos, Expression* try_expression, TryLabelExpression(SourcePosition pos, bool catch_exceptions,
LabelBlock* label_block) Expression* try_expression, LabelBlock* label_block)
: Expression(kKind, pos), : Expression(kKind, pos),
catch_exceptions(catch_exceptions),
try_expression(try_expression), try_expression(try_expression),
label_block(label_block) {} label_block(label_block) {}
bool catch_exceptions;
Expression* try_expression; Expression* try_expression;
LabelBlock* label_block; LabelBlock* label_block;
}; };
......
...@@ -18,6 +18,7 @@ void Block::SetInputTypes(const Stack<const Type*>& input_types) { ...@@ -18,6 +18,7 @@ void Block::SetInputTypes(const Stack<const Type*>& input_types) {
return; return;
} }
DCHECK_EQ(input_types.Size(), input_types_->Size());
Stack<const Type*> merged_types; Stack<const Type*> merged_types;
auto c2_iterator = input_types.begin(); auto c2_iterator = input_types.begin();
for (const Type* c1 : *input_types_) { for (const Type* c1 : *input_types_) {
......
...@@ -139,11 +139,35 @@ class CfgAssembler { ...@@ -139,11 +139,35 @@ class CfgAssembler {
void PrintCurrentStack(std::ostream& s) { s << "stack: " << current_stack_; } void PrintCurrentStack(std::ostream& s) { s << "stack: " << current_stack_; }
private: private:
friend class CfgAssemblerScopedTemporaryBlock;
Stack<const Type*> current_stack_; Stack<const Type*> current_stack_;
ControlFlowGraph cfg_; ControlFlowGraph cfg_;
Block* current_block_ = cfg_.start(); Block* current_block_ = cfg_.start();
}; };
class CfgAssemblerScopedTemporaryBlock {
public:
CfgAssemblerScopedTemporaryBlock(CfgAssembler* assembler, Block* block)
: assembler_(assembler), saved_block_(block) {
saved_stack_ = block->InputTypes();
DCHECK(!assembler->CurrentBlockIsComplete());
std::swap(saved_block_, assembler->current_block_);
std::swap(saved_stack_, assembler->current_stack_);
assembler->cfg_.PlaceBlock(block);
}
~CfgAssemblerScopedTemporaryBlock() {
DCHECK(assembler_->CurrentBlockIsComplete());
std::swap(saved_block_, assembler_->current_block_);
std::swap(saved_stack_, assembler_->current_stack_);
}
private:
CfgAssembler* assembler_;
Stack<const Type*> saved_stack_;
Block* saved_block_;
};
} // namespace torque } // namespace torque
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -150,6 +150,7 @@ void CSAGenerator::EmitInstruction(const CallCsaMacroInstruction& instruction, ...@@ -150,6 +150,7 @@ void CSAGenerator::EmitInstruction(const CallCsaMacroInstruction& instruction,
} }
std::reverse(args.begin(), args.end()); std::reverse(args.begin(), args.end());
Stack<std::string> pre_call_stack = *stack;
const Type* return_type = instruction.macro->signature().return_type; const Type* return_type = instruction.macro->signature().return_type;
std::vector<std::string> results; std::vector<std::string> results;
for (const Type* type : LowerType(return_type)) { for (const Type* type : LowerType(return_type)) {
...@@ -159,6 +160,8 @@ void CSAGenerator::EmitInstruction(const CallCsaMacroInstruction& instruction, ...@@ -159,6 +160,8 @@ void CSAGenerator::EmitInstruction(const CallCsaMacroInstruction& instruction,
<< stack->Top() << ";\n"; << stack->Top() << ";\n";
out_ << " USE(" << stack->Top() << ");\n"; out_ << " USE(" << stack->Top() << ");\n";
} }
std::string catch_name =
PreCallableExceptionPreparation(instruction.catch_block);
out_ << " "; out_ << " ";
if (return_type->IsStructType()) { if (return_type->IsStructType()) {
out_ << "std::tie("; out_ << "std::tie(";
...@@ -178,6 +181,8 @@ void CSAGenerator::EmitInstruction(const CallCsaMacroInstruction& instruction, ...@@ -178,6 +181,8 @@ void CSAGenerator::EmitInstruction(const CallCsaMacroInstruction& instruction,
if (results.size() == 1) out_ << ")"; if (results.size() == 1) out_ << ")";
out_ << ");\n"; out_ << ");\n";
} }
PostCallableExceptionPreparation(catch_name, return_type,
instruction.catch_block, &pre_call_stack);
} }
void CSAGenerator::EmitInstruction( void CSAGenerator::EmitInstruction(
...@@ -205,6 +210,7 @@ void CSAGenerator::EmitInstruction( ...@@ -205,6 +210,7 @@ void CSAGenerator::EmitInstruction(
} }
std::reverse(args.begin(), args.end()); std::reverse(args.begin(), args.end());
Stack<std::string> pre_call_stack = *stack;
std::vector<std::string> results; std::vector<std::string> results;
const Type* return_type = instruction.macro->signature().return_type; const Type* return_type = instruction.macro->signature().return_type;
if (return_type != TypeOracle::GetNeverType()) { if (return_type != TypeOracle::GetNeverType()) {
...@@ -235,6 +241,8 @@ void CSAGenerator::EmitInstruction( ...@@ -235,6 +241,8 @@ void CSAGenerator::EmitInstruction(
out_ << " Label " << label_names[i] << "(this);\n"; out_ << " Label " << label_names[i] << "(this);\n";
} }
std::string catch_name =
PreCallableExceptionPreparation(instruction.catch_block);
out_ << " "; out_ << " ";
if (results.size() == 1) { if (results.size() == 1) {
out_ << results[0] << " = "; out_ << results[0] << " = ";
...@@ -259,6 +267,10 @@ void CSAGenerator::EmitInstruction( ...@@ -259,6 +267,10 @@ void CSAGenerator::EmitInstruction(
} else { } else {
out_ << ");\n"; out_ << ");\n";
} }
PostCallableExceptionPreparation(catch_name, return_type,
instruction.catch_block, &pre_call_stack);
if (instruction.return_continuation) { if (instruction.return_continuation) {
out_ << " Goto(&" << BlockName(*instruction.return_continuation); out_ << " Goto(&" << BlockName(*instruction.return_continuation);
for (const std::string& value : *stack) { for (const std::string& value : *stack) {
...@@ -296,16 +308,24 @@ void CSAGenerator::EmitInstruction(const CallBuiltinInstruction& instruction, ...@@ -296,16 +308,24 @@ void CSAGenerator::EmitInstruction(const CallBuiltinInstruction& instruction,
PrintCommaSeparatedList(out_, arguments); PrintCommaSeparatedList(out_, arguments);
out_ << ");\n"; out_ << ");\n";
} else { } else {
std::string result_name = FreshNodeName();
if (result_types.size() == 1) {
out_ << " TNode<" << result_types[0]->GetGeneratedTNodeTypeName()
<< "> " << result_name << ";\n";
}
std::string catch_name =
PreCallableExceptionPreparation(instruction.catch_block);
Stack<std::string> pre_call_stack = *stack;
if (result_types.size() == 1) { if (result_types.size() == 1) {
std::string generated_type = result_types[0]->GetGeneratedTNodeTypeName(); std::string generated_type = result_types[0]->GetGeneratedTNodeTypeName();
stack->Push(FreshNodeName()); stack->Push(result_name);
out_ << " TNode<" << generated_type << "> " << stack->Top() << " = "; out_ << " " << result_name << " = ";
if (generated_type != "Object") out_ << "CAST("; if (generated_type != "Object") out_ << "CAST(";
out_ << "CallBuiltin(Builtins::k" << instruction.builtin->name() << ", "; out_ << "CallBuiltin(Builtins::k" << instruction.builtin->name() << ", ";
PrintCommaSeparatedList(out_, arguments); PrintCommaSeparatedList(out_, arguments);
if (generated_type != "Object") out_ << ")"; if (generated_type != "Object") out_ << ")";
out_ << ");\n"; out_ << ");\n";
out_ << " USE(" << stack->Top() << ");\n"; out_ << " USE(" << result_name << ");\n";
} else { } else {
DCHECK_EQ(0, result_types.size()); DCHECK_EQ(0, result_types.size());
// TODO(tebbi): Actually, builtins have to return a value, so we should // TODO(tebbi): Actually, builtins have to return a value, so we should
...@@ -315,6 +335,10 @@ void CSAGenerator::EmitInstruction(const CallBuiltinInstruction& instruction, ...@@ -315,6 +335,10 @@ void CSAGenerator::EmitInstruction(const CallBuiltinInstruction& instruction,
PrintCommaSeparatedList(out_, arguments); PrintCommaSeparatedList(out_, arguments);
out_ << ");\n"; out_ << ");\n";
} }
PostCallableExceptionPreparation(
catch_name,
result_types.size() == 0 ? TypeOracle::GetVoidType() : result_types[0],
instruction.catch_block, &pre_call_stack);
} }
} }
...@@ -348,6 +372,44 @@ void CSAGenerator::EmitInstruction( ...@@ -348,6 +372,44 @@ void CSAGenerator::EmitInstruction(
} }
} }
std::string CSAGenerator::PreCallableExceptionPreparation(
base::Optional<Block*> catch_block) {
std::string catch_name;
if (catch_block) {
catch_name = FreshCatchName();
out_ << " CatchLabel " << catch_name
<< "_label(this, compiler::CodeAssemblerLabel::kDeferred);\n";
out_ << " { ScopedCatch s(this, &" << catch_name << "_label);\n";
}
return catch_name;
}
void CSAGenerator::PostCallableExceptionPreparation(
const std::string& catch_name, const Type* return_type,
base::Optional<Block*> catch_block, Stack<std::string>* stack) {
if (catch_block) {
std::string block_name = BlockName(*catch_block);
out_ << " }\n";
out_ << " if (" << catch_name << "_label.is_used()) {\n";
out_ << " Label " << catch_name << "_skip(this);\n";
if (!return_type->IsNever()) {
out_ << " Goto(&" << catch_name << "_skip);\n";
}
out_ << " TNode<Object> " << catch_name << "_exception_object;\n";
out_ << " Bind(&" << catch_name << "_label, &" << catch_name
<< "_exception_object);\n";
out_ << " Goto(&" << block_name;
for (size_t i = 0; i < stack->Size(); ++i) {
out_ << ", " << stack->begin()[i];
}
out_ << ", " << catch_name << "_exception_object);\n";
if (!return_type->IsNever()) {
out_ << " Bind(&" << catch_name << "_skip);\n";
}
out_ << " }\n";
}
}
void CSAGenerator::EmitInstruction(const CallRuntimeInstruction& instruction, void CSAGenerator::EmitInstruction(const CallRuntimeInstruction& instruction,
Stack<std::string>* stack) { Stack<std::string>* stack) {
std::vector<std::string> arguments = stack->PopMany(instruction.argc); std::vector<std::string> arguments = stack->PopMany(instruction.argc);
...@@ -366,14 +428,21 @@ void CSAGenerator::EmitInstruction(const CallRuntimeInstruction& instruction, ...@@ -366,14 +428,21 @@ void CSAGenerator::EmitInstruction(const CallRuntimeInstruction& instruction,
PrintCommaSeparatedList(out_, arguments); PrintCommaSeparatedList(out_, arguments);
out_ << ");\n"; out_ << ");\n";
} else { } else {
std::string result_name = FreshNodeName();
if (result_types.size() == 1) { if (result_types.size() == 1) {
stack->Push(FreshNodeName());
out_ << " TNode<" << result_types[0]->GetGeneratedTNodeTypeName() out_ << " TNode<" << result_types[0]->GetGeneratedTNodeTypeName()
<< "> " << stack->Top() << " = CAST(CallRuntime(Runtime::k" << "> " << result_name << ";\n";
}
std::string catch_name =
PreCallableExceptionPreparation(instruction.catch_block);
Stack<std::string> pre_call_stack = *stack;
if (result_types.size() == 1) {
stack->Push(result_name);
out_ << " " << result_name << " = CAST(CallRuntime(Runtime::k"
<< instruction.runtime_function->name() << ", "; << instruction.runtime_function->name() << ", ";
PrintCommaSeparatedList(out_, arguments); PrintCommaSeparatedList(out_, arguments);
out_ << "));\n"; out_ << "));\n";
out_ << " USE(" << stack->Top() << ");\n"; out_ << " USE(" << result_name << ");\n";
} else { } else {
DCHECK_EQ(0, result_types.size()); DCHECK_EQ(0, result_types.size());
out_ << " CallRuntime(Runtime::k" out_ << " CallRuntime(Runtime::k"
...@@ -386,6 +455,8 @@ void CSAGenerator::EmitInstruction(const CallRuntimeInstruction& instruction, ...@@ -386,6 +455,8 @@ void CSAGenerator::EmitInstruction(const CallRuntimeInstruction& instruction,
DCHECK(return_type == TypeOracle::GetVoidType()); DCHECK(return_type == TypeOracle::GetVoidType());
} }
} }
PostCallableExceptionPreparation(catch_name, return_type,
instruction.catch_block, &pre_call_stack);
} }
} }
......
...@@ -32,7 +32,15 @@ class CSAGenerator { ...@@ -32,7 +32,15 @@ class CSAGenerator {
size_t fresh_id_ = 0; size_t fresh_id_ = 0;
base::Optional<Builtin::Kind> linkage_; base::Optional<Builtin::Kind> linkage_;
std::string PreCallableExceptionPreparation(
base::Optional<Block*> catch_block);
void PostCallableExceptionPreparation(const std::string& catch_name,
const Type* return_type,
base::Optional<Block*> catch_block,
Stack<std::string>* stack);
std::string FreshNodeName() { return "tmp" + std::to_string(fresh_id_++); } std::string FreshNodeName() { return "tmp" + std::to_string(fresh_id_++); }
std::string FreshCatchName() { return "catch" + std::to_string(fresh_id_++); }
std::string BlockName(const Block* block) { std::string BlockName(const Block* block) {
return "block" + std::to_string(block->id()); return "block" + std::to_string(block->id());
} }
......
...@@ -93,11 +93,14 @@ void ImplementationVisitor::BeginModuleFile(Module* module) { ...@@ -93,11 +93,14 @@ void ImplementationVisitor::BeginModuleFile(Module* module) {
source << "#include \"builtins-" + DashifyString(module->name()) + source << "#include \"builtins-" + DashifyString(module->name()) +
"-from-dsl-gen.h\"\n\n"; "-from-dsl-gen.h\"\n\n";
source << "namespace v8 {\n" source
<< "namespace internal {\n" << "namespace v8 {\n"
<< "\n" << "namespace internal {\n"
<< "using Node = compiler::Node;\n" << "\n"
<< "\n"; << "using Node = compiler::Node;\n"
<< "using CatchLabel = compiler::CodeAssemblerExceptionHandlerLabel;\n"
<< "using ScopedCatch = compiler::CodeAssemblerScopedExceptionHandler;\n"
<< "\n";
std::string upper_name(module->name()); std::string upper_name(module->name());
transform(upper_name.begin(), upper_name.end(), upper_name.begin(), transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
...@@ -1774,8 +1777,10 @@ VisitResult ImplementationVisitor::GenerateCall( ...@@ -1774,8 +1777,10 @@ VisitResult ImplementationVisitor::GenerateCall(
} }
if (auto* builtin = Builtin::DynamicCast(callable)) { if (auto* builtin = Builtin::DynamicCast(callable)) {
assembler().Emit( base::Optional<Block*> catch_block = GetCatchBlock();
CallBuiltinInstruction{is_tailcall, builtin, argument_range.Size()}); assembler().Emit(CallBuiltinInstruction{
is_tailcall, builtin, argument_range.Size(), catch_block});
GenerateCatchBlock(catch_block);
if (is_tailcall) { if (is_tailcall) {
return VisitResult::NeverResult(); return VisitResult::NeverResult();
} else { } else {
...@@ -1806,7 +1811,10 @@ VisitResult ImplementationVisitor::GenerateCall( ...@@ -1806,7 +1811,10 @@ VisitResult ImplementationVisitor::GenerateCall(
return VisitResult(return_type, result.str()); return VisitResult(return_type, result.str());
} else if (arguments.labels.empty() && } else if (arguments.labels.empty() &&
return_type != TypeOracle::GetNeverType()) { 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); size_t return_slot_count = LoweredSlotCount(return_type);
return VisitResult(return_type, assembler().TopRange(return_slot_count)); return VisitResult(return_type, assembler().TopRange(return_slot_count));
} else { } else {
...@@ -1820,9 +1828,11 @@ VisitResult ImplementationVisitor::GenerateCall( ...@@ -1820,9 +1828,11 @@ VisitResult ImplementationVisitor::GenerateCall(
for (size_t i = 0; i < label_count; ++i) { for (size_t i = 0; i < label_count; ++i) {
label_blocks.push_back(assembler().NewBlock()); label_blocks.push_back(assembler().NewBlock());
} }
base::Optional<Block*> catch_block = GetCatchBlock();
assembler().Emit(CallCsaMacroAndBranchInstruction{ 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) { for (size_t i = 0; i < label_count; ++i) {
Binding<LocalLabel>* label = arguments.labels[i]; Binding<LocalLabel>* label = arguments.labels[i];
...@@ -1862,8 +1872,10 @@ VisitResult ImplementationVisitor::GenerateCall( ...@@ -1862,8 +1872,10 @@ VisitResult ImplementationVisitor::GenerateCall(
} }
} }
} else if (auto* runtime_function = RuntimeFunction::DynamicCast(callable)) { } else if (auto* runtime_function = RuntimeFunction::DynamicCast(callable)) {
assembler().Emit(CallRuntimeInstruction{is_tailcall, runtime_function, base::Optional<Block*> catch_block = GetCatchBlock();
argument_range.Size()}); assembler().Emit(CallRuntimeInstruction{
is_tailcall, runtime_function, argument_range.Size(), catch_block});
GenerateCatchBlock(catch_block);
if (is_tailcall || return_type == TypeOracle::GetNeverType()) { if (is_tailcall || return_type == TypeOracle::GetNeverType()) {
return VisitResult::NeverResult(); return VisitResult::NeverResult();
} else { } else {
...@@ -2061,6 +2073,30 @@ bool IsCompatibleSignature(const Signature& sig, const TypeVector& types, ...@@ -2061,6 +2073,30 @@ bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
return true; 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);
}
}
}
} // namespace torque } // namespace torque
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -312,6 +312,9 @@ class ImplementationVisitor : public FileVisitor { ...@@ -312,6 +312,9 @@ class ImplementationVisitor : public FileVisitor {
std::string GetDSLAssemblerName(Module* module); std::string GetDSLAssemblerName(Module* module);
base::Optional<Block*> GetCatchBlock();
void GenerateCatchBlock(base::Optional<Block*> catch_block);
// {StackScope} records the stack height at creation time and reconstructs it // {StackScope} records the stack height at creation time and reconstructs it
// when being destructed by emitting a {DeleteRangeInstruction}, except for // when being destructed by emitting a {DeleteRangeInstruction}, except for
// the slots protected by {StackScope::Yield}. Calling {Yield(v)} deletes all // the slots protected by {StackScope::Yield}. Calling {Yield(v)} deletes all
......
...@@ -104,6 +104,12 @@ void CallCsaMacroInstruction::TypeInstruction(Stack<const Type*>* stack, ...@@ -104,6 +104,12 @@ void CallCsaMacroInstruction::TypeInstruction(Stack<const Type*>* stack,
InvalidateTransientTypes(stack); InvalidateTransientTypes(stack);
} }
if (catch_block) {
Stack<const Type*> catch_stack = *stack;
catch_stack.Push(TypeOracle::GetObjectType());
(*catch_block)->SetInputTypes(catch_stack);
}
stack->PushMany(LowerType(macro->signature().return_type)); stack->PushMany(LowerType(macro->signature().return_type));
} }
...@@ -136,6 +142,12 @@ void CallCsaMacroAndBranchInstruction::TypeInstruction( ...@@ -136,6 +142,12 @@ void CallCsaMacroAndBranchInstruction::TypeInstruction(
InvalidateTransientTypes(stack); InvalidateTransientTypes(stack);
} }
if (catch_block) {
Stack<const Type*> catch_stack = *stack;
catch_stack.Push(TypeOracle::GetObjectType());
(*catch_block)->SetInputTypes(catch_stack);
}
if (macro->signature().return_type != TypeOracle::GetNeverType()) { if (macro->signature().return_type != TypeOracle::GetNeverType()) {
Stack<const Type*> return_stack = *stack; Stack<const Type*> return_stack = *stack;
return_stack.PushMany(LowerType(macro->signature().return_type)); return_stack.PushMany(LowerType(macro->signature().return_type));
...@@ -160,6 +172,13 @@ void CallBuiltinInstruction::TypeInstruction(Stack<const Type*>* stack, ...@@ -160,6 +172,13 @@ void CallBuiltinInstruction::TypeInstruction(Stack<const Type*>* stack,
if (builtin->IsTransitioning()) { if (builtin->IsTransitioning()) {
InvalidateTransientTypes(stack); InvalidateTransientTypes(stack);
} }
if (catch_block) {
Stack<const Type*> catch_stack = *stack;
catch_stack.Push(TypeOracle::GetObjectType());
(*catch_block)->SetInputTypes(catch_stack);
}
stack->PushMany(LowerType(builtin->signature().return_type)); stack->PushMany(LowerType(builtin->signature().return_type));
} }
...@@ -188,6 +207,13 @@ void CallRuntimeInstruction::TypeInstruction(Stack<const Type*>* stack, ...@@ -188,6 +207,13 @@ void CallRuntimeInstruction::TypeInstruction(Stack<const Type*>* stack,
if (runtime_function->IsTransitioning()) { if (runtime_function->IsTransitioning()) {
InvalidateTransientTypes(stack); InvalidateTransientTypes(stack);
} }
if (catch_block) {
Stack<const Type*> catch_stack = *stack;
catch_stack.Push(TypeOracle::GetObjectType());
(*catch_block)->SetInputTypes(catch_stack);
}
const Type* return_type = runtime_function->signature().return_type; const Type* return_type = runtime_function->signature().return_type;
if (return_type != TypeOracle::GetNeverType()) { if (return_type != TypeOracle::GetNeverType()) {
stack->PushMany(LowerType(return_type)); stack->PushMany(LowerType(return_type));
......
...@@ -190,11 +190,18 @@ struct ModuleConstantInstruction : InstructionBase { ...@@ -190,11 +190,18 @@ struct ModuleConstantInstruction : InstructionBase {
struct CallCsaMacroInstruction : InstructionBase { struct CallCsaMacroInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
CallCsaMacroInstruction(Macro* macro, CallCsaMacroInstruction(Macro* macro,
std::vector<std::string> constexpr_arguments) std::vector<std::string> constexpr_arguments,
: macro(macro), constexpr_arguments(constexpr_arguments) {} base::Optional<Block*> catch_block)
: macro(macro),
constexpr_arguments(constexpr_arguments),
catch_block(catch_block) {}
void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
if (catch_block) block_list->push_back(*catch_block);
}
Macro* macro; Macro* macro;
std::vector<std::string> constexpr_arguments; std::vector<std::string> constexpr_arguments;
base::Optional<Block*> catch_block;
}; };
struct CallCsaMacroAndBranchInstruction : InstructionBase { struct CallCsaMacroAndBranchInstruction : InstructionBase {
...@@ -202,13 +209,16 @@ struct CallCsaMacroAndBranchInstruction : InstructionBase { ...@@ -202,13 +209,16 @@ struct CallCsaMacroAndBranchInstruction : InstructionBase {
CallCsaMacroAndBranchInstruction(Macro* macro, CallCsaMacroAndBranchInstruction(Macro* macro,
std::vector<std::string> constexpr_arguments, std::vector<std::string> constexpr_arguments,
base::Optional<Block*> return_continuation, base::Optional<Block*> return_continuation,
std::vector<Block*> label_blocks) std::vector<Block*> label_blocks,
base::Optional<Block*> catch_block)
: macro(macro), : macro(macro),
constexpr_arguments(constexpr_arguments), constexpr_arguments(constexpr_arguments),
return_continuation(return_continuation), return_continuation(return_continuation),
label_blocks(label_blocks) {} label_blocks(label_blocks),
catch_block(catch_block) {}
bool IsBlockTerminator() const override { return true; } bool IsBlockTerminator() const override { return true; }
void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override { void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
if (catch_block) block_list->push_back(*catch_block);
if (return_continuation) block_list->push_back(*return_continuation); if (return_continuation) block_list->push_back(*return_continuation);
for (Block* block : label_blocks) block_list->push_back(block); for (Block* block : label_blocks) block_list->push_back(block);
} }
...@@ -217,17 +227,26 @@ struct CallCsaMacroAndBranchInstruction : InstructionBase { ...@@ -217,17 +227,26 @@ struct CallCsaMacroAndBranchInstruction : InstructionBase {
std::vector<std::string> constexpr_arguments; std::vector<std::string> constexpr_arguments;
base::Optional<Block*> return_continuation; base::Optional<Block*> return_continuation;
std::vector<Block*> label_blocks; std::vector<Block*> label_blocks;
base::Optional<Block*> catch_block;
}; };
struct CallBuiltinInstruction : InstructionBase { struct CallBuiltinInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override { return is_tailcall; } bool IsBlockTerminator() const override { return is_tailcall; }
CallBuiltinInstruction(bool is_tailcall, Builtin* builtin, size_t argc) CallBuiltinInstruction(bool is_tailcall, Builtin* builtin, size_t argc,
: is_tailcall(is_tailcall), builtin(builtin), argc(argc) {} base::Optional<Block*> catch_block)
: is_tailcall(is_tailcall),
builtin(builtin),
argc(argc),
catch_block(catch_block) {}
void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
if (catch_block) block_list->push_back(*catch_block);
}
bool is_tailcall; bool is_tailcall;
Builtin* builtin; Builtin* builtin;
size_t argc; size_t argc;
base::Optional<Block*> catch_block;
}; };
struct CallBuiltinPointerInstruction : InstructionBase { struct CallBuiltinPointerInstruction : InstructionBase {
...@@ -249,14 +268,19 @@ struct CallRuntimeInstruction : InstructionBase { ...@@ -249,14 +268,19 @@ struct CallRuntimeInstruction : InstructionBase {
bool IsBlockTerminator() const override; bool IsBlockTerminator() const override;
CallRuntimeInstruction(bool is_tailcall, RuntimeFunction* runtime_function, CallRuntimeInstruction(bool is_tailcall, RuntimeFunction* runtime_function,
size_t argc) size_t argc, base::Optional<Block*> catch_block)
: is_tailcall(is_tailcall), : is_tailcall(is_tailcall),
runtime_function(runtime_function), runtime_function(runtime_function),
argc(argc) {} argc(argc),
catch_block(catch_block) {}
void AppendSuccessorBlocks(std::vector<Block*>* block_list) const override {
if (catch_block) block_list->push_back(*catch_block);
}
bool is_tailcall; bool is_tailcall;
RuntimeFunction* runtime_function; RuntimeFunction* runtime_function;
size_t argc; size_t argc;
base::Optional<Block*> catch_block;
}; };
struct BranchInstruction : InstructionBase { struct BranchInstruction : InstructionBase {
......
...@@ -39,6 +39,7 @@ enum class ParseResultHolderBase::TypeId { ...@@ -39,6 +39,7 @@ enum class ParseResultHolderBase::TypeId {
kDeclarationPtr, kDeclarationPtr,
kTypeExpressionPtr, kTypeExpressionPtr,
kLabelBlockPtr, kLabelBlockPtr,
kOptionalLabelBlockPtr,
kNameAndTypeExpression, kNameAndTypeExpression,
kStdVectorOfNameAndTypeExpression, kStdVectorOfNameAndTypeExpression,
kIncrementDecrementOperator, kIncrementDecrementOperator,
...@@ -82,6 +83,10 @@ template <> ...@@ -82,6 +83,10 @@ template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<LabelBlock*>::id = V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<LabelBlock*>::id =
ParseResultTypeId::kLabelBlockPtr; ParseResultTypeId::kLabelBlockPtr;
template <> template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<base::Optional<LabelBlock*>>::id =
ParseResultTypeId::kOptionalLabelBlockPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<Expression*>::id = V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<Expression*>::id =
ParseResultTypeId::kExpressionPtr; ParseResultTypeId::kExpressionPtr;
template <> template <>
...@@ -235,7 +240,7 @@ Expression* MakeCall(const std::string& callee, bool is_operator, ...@@ -235,7 +240,7 @@ Expression* MakeCall(const std::string& callee, bool is_operator,
Expression* result = MakeNode<CallExpression>( Expression* result = MakeNode<CallExpression>(
callee, false, generic_arguments, arguments, labels); callee, false, generic_arguments, arguments, labels);
for (auto* label : temp_labels) { for (auto* label : temp_labels) {
result = MakeNode<TryLabelExpression>(result, label); result = MakeNode<TryLabelExpression>(false, result, label);
} }
return result; return result;
} }
...@@ -671,7 +676,7 @@ base::Optional<ParseResult> MakeTypeswitchStatement( ...@@ -671,7 +676,7 @@ base::Optional<ParseResult> MakeTypeswitchStatement(
BlockStatement* next_block = MakeNode<BlockStatement>(); BlockStatement* next_block = MakeNode<BlockStatement>();
current_block->statements.push_back( current_block->statements.push_back(
MakeNode<ExpressionStatement>(MakeNode<TryLabelExpression>( MakeNode<ExpressionStatement>(MakeNode<TryLabelExpression>(
MakeNode<StatementExpression>(case_block), false, MakeNode<StatementExpression>(case_block),
MakeNode<LabelBlock>("_NextCase", ParameterList::Empty(), MakeNode<LabelBlock>("_NextCase", ParameterList::Empty(),
next_block)))); next_block))));
current_block = next_block; current_block = next_block;
...@@ -772,9 +777,14 @@ base::Optional<ParseResult> MakeTryLabelExpression( ...@@ -772,9 +777,14 @@ base::Optional<ParseResult> MakeTryLabelExpression(
CheckNotDeferredStatement(try_block); CheckNotDeferredStatement(try_block);
Statement* result = try_block; Statement* result = try_block;
auto label_blocks = child_results->NextAs<std::vector<LabelBlock*>>(); auto label_blocks = child_results->NextAs<std::vector<LabelBlock*>>();
auto catch_block = child_results->NextAs<base::Optional<LabelBlock*>>();
for (auto block : label_blocks) { for (auto block : label_blocks) {
result = MakeNode<ExpressionStatement>(MakeNode<TryLabelExpression>( result = MakeNode<ExpressionStatement>(MakeNode<TryLabelExpression>(
MakeNode<StatementExpression>(result), block)); false, MakeNode<StatementExpression>(result), block));
}
if (catch_block) {
result = MakeNode<ExpressionStatement>(MakeNode<TryLabelExpression>(
true, MakeNode<StatementExpression>(result), *catch_block));
} }
return ParseResult{result}; return ParseResult{result};
} }
...@@ -818,6 +828,21 @@ base::Optional<ParseResult> MakeLabelBlock(ParseResultIterator* child_results) { ...@@ -818,6 +828,21 @@ base::Optional<ParseResult> MakeLabelBlock(ParseResultIterator* child_results) {
return ParseResult{result}; return ParseResult{result};
} }
base::Optional<ParseResult> MakeCatchBlock(ParseResultIterator* child_results) {
auto variable = child_results->NextAs<std::string>();
auto body = child_results->NextAs<Statement*>();
if (!IsLowerCamelCase(variable)) {
NamingConventionError("Exception", variable, "lowerCamelCase");
}
ParameterList parameters;
parameters.names.push_back(variable);
parameters.types.push_back(MakeNode<BasicTypeExpression>(false, "Object"));
parameters.has_varargs = false;
LabelBlock* result =
MakeNode<LabelBlock>("_catch", std::move(parameters), body);
return ParseResult{result};
}
base::Optional<ParseResult> MakeRangeExpression( base::Optional<ParseResult> MakeRangeExpression(
ParseResultIterator* child_results) { ParseResultIterator* child_results) {
auto begin = child_results->NextAs<base::Optional<Expression*>>(); auto begin = child_results->NextAs<base::Optional<Expression*>>();
...@@ -1279,6 +1304,10 @@ struct TorqueGrammar : Grammar { ...@@ -1279,6 +1304,10 @@ struct TorqueGrammar : Grammar {
TryOrDefault<ParameterList>(&parameterListNoVararg), &block}, TryOrDefault<ParameterList>(&parameterListNoVararg), &block},
MakeLabelBlock)}; MakeLabelBlock)};
Symbol catchBlock = {
Rule({Token("catch"), Token("("), &identifier, Token(")"), &block},
MakeCatchBlock)};
// Result: ExpressionWithSource // Result: ExpressionWithSource
Symbol expressionWithSource = {Rule({expression}, MakeExpressionWithSource)}; Symbol expressionWithSource = {Rule({expression}, MakeExpressionWithSource)};
...@@ -1329,7 +1358,8 @@ struct TorqueGrammar : Grammar { ...@@ -1329,7 +1358,8 @@ struct TorqueGrammar : Grammar {
Token("}"), Token("}"),
}, },
MakeTypeswitchStatement), MakeTypeswitchStatement),
Rule({Token("try"), &block, NonemptyList<LabelBlock*>(&labelBlock)}, Rule({Token("try"), &block, List<LabelBlock*>(&labelBlock),
Optional<LabelBlock*>(&catchBlock)},
MakeTryLabelExpression), MakeTryLabelExpression),
Rule({OneOf({"assert", "check"}), Token("("), &expressionWithSource, Rule({OneOf({"assert", "check"}), Token("("), &expressionWithSource,
Token(")"), Token(";")}, Token(")"), Token(";")},
......
...@@ -286,6 +286,63 @@ TEST(TestOtherwiseAndLabels) { ...@@ -286,6 +286,63 @@ TEST(TestOtherwiseAndLabels) {
ft.Call(); ft.Call();
} }
TEST(TestCatch1) {
CcTest::InitializeVM();
Isolate* isolate(CcTest::i_isolate());
i::HandleScope scope(isolate);
Handle<Context> context =
Utils::OpenHandle(*v8::Isolate::GetCurrent()->GetCurrentContext());
CodeAssemblerTester asm_tester(isolate, 0);
TestBuiltinsFromDSLAssembler m(asm_tester.state());
{
TNode<Smi> result =
m.TestCatch1(m.UncheckedCast<Context>(m.HeapConstant(context)));
USE(result);
CSA_ASSERT(&m, m.WordEqual(result, m.SmiConstant(1)));
m.Return(m.UndefinedConstant());
}
FunctionTester ft(asm_tester.GenerateCode(), 0);
ft.Call();
}
TEST(TestCatch2) {
CcTest::InitializeVM();
Isolate* isolate(CcTest::i_isolate());
i::HandleScope scope(isolate);
Handle<Context> context =
Utils::OpenHandle(*v8::Isolate::GetCurrent()->GetCurrentContext());
CodeAssemblerTester asm_tester(isolate, 0);
TestBuiltinsFromDSLAssembler m(asm_tester.state());
{
TNode<Smi> result =
m.TestCatch2(m.UncheckedCast<Context>(m.HeapConstant(context)));
USE(result);
CSA_ASSERT(&m, m.WordEqual(result, m.SmiConstant(2)));
m.Return(m.UndefinedConstant());
}
FunctionTester ft(asm_tester.GenerateCode(), 0);
ft.Call();
}
TEST(TestCatch3) {
CcTest::InitializeVM();
Isolate* isolate(CcTest::i_isolate());
i::HandleScope scope(isolate);
Handle<Context> context =
Utils::OpenHandle(*v8::Isolate::GetCurrent()->GetCurrentContext());
CodeAssemblerTester asm_tester(isolate, 0);
TestBuiltinsFromDSLAssembler m(asm_tester.state());
{
TNode<Smi> result =
m.TestCatch3(m.UncheckedCast<Context>(m.HeapConstant(context)));
USE(result);
CSA_ASSERT(&m, m.WordEqual(result, m.SmiConstant(2)));
m.Return(m.UndefinedConstant());
}
FunctionTester ft(asm_tester.GenerateCode(), 0);
ft.Call();
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -598,4 +598,47 @@ module test { ...@@ -598,4 +598,47 @@ module test {
assert(b == 5); assert(b == 5);
} }
} }
macro TestCatch1(context: Context): Smi {
let r: Smi = 0;
try {
ThrowTypeError(context, kInvalidArrayLength);
} catch (e) {
r = 1;
return r;
}
}
macro TestCatch2Wrapper(context: Context): never {
ThrowTypeError(context, kInvalidArrayLength);
}
macro TestCatch2(context: Context): Smi {
let r: Smi = 0;
try {
TestCatch2Wrapper(context);
} catch (e) {
r = 2;
return r;
}
}
macro TestCatch3WrapperWithLabel(context: Context): never
labels Abort {
ThrowTypeError(context, kInvalidArrayLength);
}
macro TestCatch3(context: Context): Smi {
let r: Smi = 0;
try {
TestCatch3WrapperWithLabel(context) otherwise Abort;
}
label Abort {
return -1;
}
catch (e) {
r = 2;
return r;
}
}
} }
...@@ -29,7 +29,7 @@ syn match torqueConstant /\v<k[A-Z][A-Za-z0-9]*>/ ...@@ -29,7 +29,7 @@ syn match torqueConstant /\v<k[A-Z][A-Za-z0-9]*>/
syn keyword torqueFunction macro builtin runtime syn keyword torqueFunction macro builtin runtime
syn keyword torqueKeyword cast convert from_constexpr min max unsafe_cast syn keyword torqueKeyword cast convert from_constexpr min max unsafe_cast
syn keyword torqueLabel case syn keyword torqueLabel case
syn keyword torqueMatching try label syn keyword torqueMatching try label catch
syn keyword torqueModifier extern javascript constexpr transitioning transient syn keyword torqueModifier extern javascript constexpr transitioning transient
syn match torqueNumber /\v<[0-9]+(\.[0-9]*)?>/ syn match torqueNumber /\v<[0-9]+(\.[0-9]*)?>/
syn match torqueNumber /\v<0x[0-9a-fA-F]+>/ syn match torqueNumber /\v<0x[0-9a-fA-F]+>/
......
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
"keywords": { "keywords": {
"patterns": [{ "patterns": [{
"name": "keyword.control.torque", "name": "keyword.control.torque",
"match": "\\b(if|else|while|for|return|continue|break|goto|otherwise|try|catch)\\b" "match": "\\b(if|else|while|for|return|continue|break|goto|otherwise|try|label|catch)\\b"
}, },
{ {
"name": "keyword.other.torque", "name": "keyword.other.torque",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment