Commit 1b37ea71 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[compiler] Remove error-prone GotoIfException

... in favor of CodeAssembler's ScopedExceptionHandler.

Also remove unused exception arguments from some iterator
related methods.

Bug: v8:10187
Change-Id: I8eb7dfd4eb339e4f566970efa5757c3771926ba6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2060496
Commit-Queue: Georg Neis <neis@chromium.org>
Auto-Submit: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66306}
parent 5d7f29ac
......@@ -13,8 +13,6 @@
namespace v8 {
namespace internal {
using compiler::Node;
namespace {
class AsyncFromSyncBuiltinsAssembler : public AsyncBuiltinsAssembler {
public:
......@@ -130,9 +128,12 @@ void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod(
BIND(&if_isnotundefined);
}
const TNode<Object> iter_result = CallJS(
CodeFactory::Call(isolate()), context, method, sync_iterator, sent_value);
GotoIfException(iter_result, &reject_promise, &var_exception);
TNode<Object> iter_result;
{
ScopedExceptionHandler handler(this, &reject_promise, &var_exception);
iter_result = CallJS(CodeFactory::Call(isolate()), context, method,
sync_iterator, sent_value);
}
TNode<Object> value;
TNode<Oddball> done;
......@@ -144,10 +145,13 @@ void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod(
CSA_ASSERT(this, IsConstructor(promise_fun));
// Let valueWrapper be PromiseResolve(%Promise%, « value »).
const TNode<Object> value_wrapper = CallBuiltin(
Builtins::kPromiseResolve, native_context, promise_fun, value);
// IfAbruptRejectPromise(valueWrapper, promiseCapability).
GotoIfException(value_wrapper, &reject_promise, &var_exception);
TNode<Object> value_wrapper;
{
ScopedExceptionHandler handler(this, &reject_promise, &var_exception);
value_wrapper = CallBuiltin(Builtins::kPromiseResolve, native_context,
promise_fun, value);
}
// Let onFulfilled be a new built-in function object as defined in
// Async Iterator Value Unwrap Functions.
......@@ -200,17 +204,17 @@ AsyncFromSyncBuiltinsAssembler::LoadIteratorResult(
BIND(&if_slowpath);
{
ScopedExceptionHandler handler(this, if_exception, var_exception);
// Let nextDone be IteratorComplete(nextResult).
// IfAbruptRejectPromise(nextDone, promiseCapability).
const TNode<Object> done =
GetProperty(context, iter_result, factory()->done_string());
GotoIfException(done, if_exception, var_exception);
// Let nextValue be IteratorValue(nextResult).
// IfAbruptRejectPromise(nextValue, promiseCapability).
const TNode<Object> value =
GetProperty(context, iter_result, factory()->value_string());
GotoIfException(value, if_exception, var_exception);
var_value = value;
var_done = done;
......
......@@ -150,8 +150,7 @@ void BaseCollectionsAssembler::AddConstructorEntry(
TNode<Object> add_function, TNode<Object> key_value,
Label* if_may_have_side_effects, Label* if_exception,
TVariable<Object>* var_exception) {
compiler::CodeAssemblerScopedExceptionHandler handler(this, if_exception,
var_exception);
compiler::ScopedExceptionHandler handler(this, if_exception, var_exception);
CSA_ASSERT(this, Word32BinaryNot(IsTheHole(key_value)));
if (variant == kMap || variant == kWeakMap) {
TorqueStructKeyValuePair pair =
......
......@@ -56,12 +56,16 @@ void GeneratorBuiltinsAssembler::InnerResume(
SmiConstant(resume_mode));
// Resume the {receiver} using our trampoline.
// Close the generator if there was an exception.
TVARIABLE(Object, var_exception);
Label if_exception(this, Label::kDeferred), if_final_return(this);
TNode<Object> result = CallStub(CodeFactory::ResumeGenerator(isolate()),
context, value, receiver);
// Make sure we close the generator if there was an exception.
GotoIfException(result, &if_exception, &var_exception);
TNode<Object> result;
{
compiler::ScopedExceptionHandler handler(this, &if_exception,
&var_exception);
result = CallStub(CodeFactory::ResumeGenerator(isolate()), context, value,
receiver);
}
// If the generator is not suspended (i.e., its state is 'executing'),
// close it and wrap the return value in IteratorResult.
......
......@@ -23,53 +23,39 @@ TNode<Object> IteratorBuiltinsAssembler::GetIteratorMethod(
return GetProperty(context, object, factory()->iterator_symbol());
}
IteratorRecord IteratorBuiltinsAssembler::GetIterator(
TNode<Context> context, TNode<Object> object, Label* if_exception,
TVariable<Object>* exception) {
IteratorRecord IteratorBuiltinsAssembler::GetIterator(TNode<Context> context,
TNode<Object> object) {
TNode<Object> method = GetIteratorMethod(context, object);
return GetIterator(context, object, method, if_exception, exception);
return GetIterator(context, object, method);
}
IteratorRecord IteratorBuiltinsAssembler::GetIterator(
TNode<Context> context, TNode<Object> object, TNode<Object> method,
Label* if_exception, TVariable<Object>* exception) {
GotoIfException(method, if_exception, exception);
IteratorRecord IteratorBuiltinsAssembler::GetIterator(TNode<Context> context,
TNode<Object> object,
TNode<Object> method) {
Label if_not_callable(this, Label::kDeferred), if_callable(this);
GotoIf(TaggedIsSmi(method), &if_not_callable);
Branch(IsCallable(CAST(method)), &if_callable, &if_not_callable);
BIND(&if_not_callable);
{
TNode<Object> ret =
CallRuntime(Runtime::kThrowIteratorError, context, object);
GotoIfException(ret, if_exception, exception);
Unreachable();
}
CallRuntime(Runtime::kThrowIteratorError, context, object);
Unreachable();
BIND(&if_callable);
{
Callable callable = CodeFactory::Call(isolate());
TNode<Object> iterator = CallJS(callable, context, method, object);
GotoIfException(iterator, if_exception, exception);
TNode<Object> iterator =
CallJS(CodeFactory::Call(isolate()), context, method, object);
Label get_next(this), if_notobject(this, Label::kDeferred);
GotoIf(TaggedIsSmi(iterator), &if_notobject);
Branch(IsJSReceiver(CAST(iterator)), &get_next, &if_notobject);
BIND(&if_notobject);
{
TNode<Object> ret =
CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context);
GotoIfException(ret, if_exception, exception);
Unreachable();
}
CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context);
Unreachable();
BIND(&get_next);
const TNode<Object> next =
TNode<Object> next =
GetProperty(context, iterator, factory()->next_string());
GotoIfException(next, if_exception, exception);
return IteratorRecord{TNode<JSReceiver>::UncheckedCast(iterator),
TNode<Object>::UncheckedCast(next)};
}
......@@ -77,14 +63,12 @@ IteratorRecord IteratorBuiltinsAssembler::GetIterator(
TNode<JSReceiver> IteratorBuiltinsAssembler::IteratorStep(
TNode<Context> context, const IteratorRecord& iterator, Label* if_done,
base::Optional<TNode<Map>> fast_iterator_result_map, Label* if_exception,
TVariable<Object>* exception) {
base::Optional<TNode<Map>> fast_iterator_result_map) {
DCHECK_NOT_NULL(if_done);
// 1. a. Let result be ? Invoke(iterator, "next", « »).
Callable callable = CodeFactory::Call(isolate());
TNode<Object> result =
CallJS(callable, context, iterator.next, iterator.object);
GotoIfException(result, if_exception, exception);
// 3. If Type(result) is not Object, throw a TypeError exception.
Label if_notobject(this, Label::kDeferred), return_result(this);
......@@ -117,17 +101,12 @@ TNode<JSReceiver> IteratorBuiltinsAssembler::IteratorStep(
// 2. Return ToBoolean(? Get(iterResult, "done")).
TNode<Object> done =
GetProperty(context, heap_object_result, factory()->done_string());
GotoIfException(done, if_exception, exception);
BranchIfToBooleanIsTrue(done, if_done, &return_result);
}
BIND(&if_notobject);
{
TNode<Object> ret =
CallRuntime(Runtime::kThrowIteratorResultNotAnObject, context, result);
GotoIfException(ret, if_exception, exception);
Unreachable();
}
CallRuntime(Runtime::kThrowIteratorResultNotAnObject, context, result);
Unreachable();
BIND(&return_result);
return CAST(heap_object_result);
......@@ -135,8 +114,7 @@ TNode<JSReceiver> IteratorBuiltinsAssembler::IteratorStep(
TNode<Object> IteratorBuiltinsAssembler::IteratorValue(
TNode<Context> context, TNode<JSReceiver> result,
base::Optional<TNode<Map>> fast_iterator_result_map, Label* if_exception,
TVariable<Object>* exception) {
base::Optional<TNode<Map>> fast_iterator_result_map) {
Label exit(this);
TVARIABLE(Object, var_value);
if (fast_iterator_result_map) {
......@@ -151,13 +129,8 @@ TNode<Object> IteratorBuiltinsAssembler::IteratorValue(
}
// Generic iterator result case:
{
TNode<Object> value =
GetProperty(context, result, factory()->value_string());
GotoIfException(value, if_exception, exception);
var_value = value;
Goto(&exit);
}
var_value = GetProperty(context, result, factory()->value_string());
Goto(&exit);
BIND(&exit);
return var_value.value();
......@@ -174,23 +147,24 @@ void IteratorBuiltinsAssembler::IteratorCloseOnException(
CSA_ASSERT(this, IsJSReceiver(iterator.object));
// Let return be ? GetMethod(iterator, "return").
TNode<Object> method =
GetProperty(context, iterator.object, factory()->return_string());
GotoIfException(method, if_exception, exception);
TNode<Object> method;
{
compiler::ScopedExceptionHandler handler(this, if_exception, exception);
method = GetProperty(context, iterator.object, factory()->return_string());
}
// If return is undefined, return Completion(completion).
GotoIf(Word32Or(IsUndefined(method), IsNull(method)), if_exception);
{
// Let innerResult be Call(return, iterator, « »).
// If an exception occurs, the original exception remains bound
TNode<Object> inner_result =
CallJS(CodeFactory::Call(isolate()), context, method, iterator.object);
GotoIfException(inner_result, if_exception, nullptr);
// (If completion.[[Type]] is throw) return Completion(completion).
Goto(if_exception);
// If an exception occurs, the original exception remains bound.
compiler::ScopedExceptionHandler handler(this, if_exception, nullptr);
CallJS(CodeFactory::Call(isolate()), context, method, iterator.object);
}
// (If completion.[[Type]] is throw) return Completion(completion).
Goto(if_exception);
}
void IteratorBuiltinsAssembler::IteratorCloseOnException(
......@@ -317,10 +291,13 @@ TNode<JSArray> IteratorBuiltinsAssembler::StringListFromIterable(
{
// 1. Let error be ThrowCompletion(a newly created TypeError object).
TVARIABLE(Object, var_exception);
TNode<Object> ret = CallRuntime(
Runtime::kThrowTypeError, context,
SmiConstant(MessageTemplate::kIterableYieldedNonString), next_value);
GotoIfException(ret, &if_exception, &var_exception);
{
compiler::ScopedExceptionHandler handler(this, &if_exception,
&var_exception);
CallRuntime(Runtime::kThrowTypeError, context,
SmiConstant(MessageTemplate::kIterableYieldedNonString),
next_value);
}
Unreachable();
// 2. Return ? IteratorClose(iteratorRecord, error).
......
......@@ -24,13 +24,9 @@ class IteratorBuiltinsAssembler : public CodeStubAssembler {
// https://tc39.github.io/ecma262/#sec-getiterator --- never used for
// @@asyncIterator.
IteratorRecord GetIterator(TNode<Context> context, TNode<Object> object);
IteratorRecord GetIterator(TNode<Context> context, TNode<Object> object,
Label* if_exception = nullptr,
TVariable<Object>* exception = nullptr);
IteratorRecord GetIterator(TNode<Context> context, TNode<Object> object,
TNode<Object> method,
Label* if_exception = nullptr,
TVariable<Object>* exception = nullptr);
TNode<Object> method);
// https://tc39.github.io/ecma262/#sec-iteratorstep
// If the iterator is done, goto {if_done}, otherwise returns an iterator
......@@ -39,9 +35,7 @@ class IteratorBuiltinsAssembler : public CodeStubAssembler {
// object, loaded from the native context.
TNode<JSReceiver> IteratorStep(
TNode<Context> context, const IteratorRecord& iterator, Label* if_done,
base::Optional<TNode<Map>> fast_iterator_result_map = base::nullopt,
Label* if_exception = nullptr, TVariable<Object>* exception = nullptr);
base::Optional<TNode<Map>> fast_iterator_result_map = base::nullopt);
TNode<JSReceiver> IteratorStep(
TNode<Context> context, const IteratorRecord& iterator,
base::Optional<TNode<Map>> fast_iterator_result_map, Label* if_done) {
......@@ -54,8 +48,7 @@ class IteratorBuiltinsAssembler : public CodeStubAssembler {
// object, loaded from the native context.
TNode<Object> IteratorValue(
TNode<Context> context, TNode<JSReceiver> result,
base::Optional<TNode<Map>> fast_iterator_result_map = base::nullopt,
Label* if_exception = nullptr, TVariable<Object>* exception = nullptr);
base::Optional<TNode<Map>> fast_iterator_result_map = base::nullopt);
// https://tc39.github.io/ecma262/#sec-iteratorclose
void IteratorCloseOnException(TNode<Context> context,
......
......@@ -118,7 +118,7 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
TNode<Map> microtask_map = LoadMap(microtask);
TNode<Uint16T> microtask_type = LoadMapInstanceType(microtask_map);
TVARIABLE(HeapObject, var_exception, TheHoleConstant());
TVARIABLE(Object, var_exception);
Label if_exception(this, Label::kDeferred);
Label is_callable(this), is_callback(this),
is_promise_fulfill_reaction_job(this),
......@@ -147,10 +147,12 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
TNode<JSReceiver> callable =
LoadObjectField<JSReceiver>(microtask, CallableTask::kCallableOffset);
const TNode<Object> result = CallJS(
CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
microtask_context, callable, UndefinedConstant());
GotoIfException(result, &if_exception, &var_exception);
{
ScopedExceptionHandler handler(this, &if_exception, &var_exception);
CallJS(
CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
microtask_context, callable, UndefinedConstant());
}
RewindEnteredContext(saved_entered_context_count);
SetCurrentContext(current_context);
Goto(&done);
......@@ -173,10 +175,11 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
// But from our current measurements it doesn't seem to be a
// serious performance problem, even if the microtask is full
// of CallHandlerTasks (which is not a realistic use case anyways).
const TNode<Object> result =
CallRuntime(Runtime::kRunMicrotaskCallback, current_context,
microtask_callback, microtask_data);
GotoIfException(result, &if_exception, &var_exception);
{
ScopedExceptionHandler handler(this, &if_exception, &var_exception);
CallRuntime(Runtime::kRunMicrotaskCallback, current_context,
microtask_callback, microtask_data);
}
Goto(&done);
}
......@@ -195,10 +198,11 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
const TNode<Object> thenable = LoadObjectField(
microtask, PromiseResolveThenableJobTask::kThenableOffset);
const TNode<Object> result =
CallBuiltin(Builtins::kPromiseResolveThenableJob, native_context,
promise_to_resolve, thenable, then);
GotoIfException(result, &if_exception, &var_exception);
{
ScopedExceptionHandler handler(this, &if_exception, &var_exception);
CallBuiltin(Builtins::kPromiseResolveThenableJob, native_context,
promise_to_resolve, thenable, then);
}
RewindEnteredContext(saved_entered_context_count);
SetCurrentContext(current_context);
Goto(&done);
......@@ -214,7 +218,7 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
const TNode<Object> argument =
LoadObjectField(microtask, PromiseReactionJobTask::kArgumentOffset);
const TNode<Object> handler =
const TNode<Object> job_handler =
LoadObjectField(microtask, PromiseReactionJobTask::kHandlerOffset);
const TNode<HeapObject> promise_or_capability = CAST(LoadObjectField(
microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset));
......@@ -223,10 +227,11 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
promise_or_capability);
const TNode<Object> result =
CallBuiltin(Builtins::kPromiseFulfillReactionJob, microtask_context,
argument, handler, promise_or_capability);
GotoIfException(result, &if_exception, &var_exception);
{
ScopedExceptionHandler handler(this, &if_exception, &var_exception);
CallBuiltin(Builtins::kPromiseFulfillReactionJob, microtask_context,
argument, job_handler, promise_or_capability);
}
// Run the promise after/debug hook if enabled.
RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context,
......@@ -247,7 +252,7 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
const TNode<Object> argument =
LoadObjectField(microtask, PromiseReactionJobTask::kArgumentOffset);
const TNode<Object> handler =
const TNode<Object> job_handler =
LoadObjectField(microtask, PromiseReactionJobTask::kHandlerOffset);
const TNode<HeapObject> promise_or_capability = CAST(LoadObjectField(
microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset));
......@@ -256,10 +261,11 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
promise_or_capability);
const TNode<Object> result =
CallBuiltin(Builtins::kPromiseRejectReactionJob, microtask_context,
argument, handler, promise_or_capability);
GotoIfException(result, &if_exception, &var_exception);
{
ScopedExceptionHandler handler(this, &if_exception, &var_exception);
CallBuiltin(Builtins::kPromiseRejectReactionJob, microtask_context,
argument, job_handler, promise_or_capability);
}
// Run the promise after/debug hook if enabled.
RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context,
......
......@@ -274,6 +274,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
public TorqueGeneratedExportedMacrosAssembler {
public:
using Node = compiler::Node;
using ScopedExceptionHandler = compiler::ScopedExceptionHandler;
template <typename T>
using LazyNode = std::function<TNode<T>()>;
......
......@@ -811,35 +811,6 @@ Node* CodeAssembler::Projection(int index, Node* value) {
return raw_assembler()->Projection(index, value);
}
void CodeAssembler::GotoIfException(Node* node, Label* if_exception,
Variable* exception_var) {
if (if_exception == nullptr) {
// If no handler is supplied, don't add continuations
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));
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);
if (exception_var != nullptr) {
exception_var->Bind(exception_value);
}
Goto(if_exception);
Bind(&success);
raw_assembler()->AddNode(raw_assembler()->common()->IfSuccess(), node);
}
TNode<HeapObject> CodeAssembler::OptimizedAllocate(
TNode<IntPtrT> size, AllocationType allocation,
AllowLargeObjects allow_large_objects) {
......@@ -1558,7 +1529,7 @@ void CodeAssemblerState::PopExceptionHandler() {
exception_handler_labels_.pop_back();
}
CodeAssemblerScopedExceptionHandler::CodeAssemblerScopedExceptionHandler(
ScopedExceptionHandler::ScopedExceptionHandler(
CodeAssembler* assembler, CodeAssemblerExceptionHandlerLabel* label)
: has_handler_(label != nullptr),
assembler_(assembler),
......@@ -1569,7 +1540,7 @@ CodeAssemblerScopedExceptionHandler::CodeAssemblerScopedExceptionHandler(
}
}
CodeAssemblerScopedExceptionHandler::CodeAssemblerScopedExceptionHandler(
ScopedExceptionHandler::ScopedExceptionHandler(
CodeAssembler* assembler, CodeAssemblerLabel* label,
TypedCodeAssemblerVariable<Object>* exception)
: has_handler_(label != nullptr),
......@@ -1583,7 +1554,7 @@ CodeAssemblerScopedExceptionHandler::CodeAssemblerScopedExceptionHandler(
}
}
CodeAssemblerScopedExceptionHandler::~CodeAssemblerScopedExceptionHandler() {
ScopedExceptionHandler::~ScopedExceptionHandler() {
if (has_handler_) {
assembler_->state()->PopExceptionHandler();
}
......@@ -1595,7 +1566,7 @@ CodeAssemblerScopedExceptionHandler::~CodeAssemblerScopedExceptionHandler() {
}
TNode<Object> e;
assembler_->Bind(label_.get(), &e);
*exception_ = e;
if (exception_ != nullptr) *exception_ = e;
assembler_->Goto(compatibility_label_);
if (inside_block) {
assembler_->Bind(&skip);
......
......@@ -1113,10 +1113,6 @@ class V8_EXPORT_PRIVATE CodeAssembler {
{cargs...});
}
// Exception handling support.
void GotoIfException(Node* node, Label* if_exception,
Variable* exception_var = nullptr);
// Helpers which delegate to RawMachineAssembler.
Factory* factory() const;
Isolate* isolate() const;
......@@ -1419,7 +1415,7 @@ class V8_EXPORT_PRIVATE CodeAssemblerState {
friend class CodeAssemblerVariable;
friend class CodeAssemblerTester;
friend class CodeAssemblerParameterizedLabelBase;
friend class CodeAssemblerScopedExceptionHandler;
friend class ScopedExceptionHandler;
CodeAssemblerState(Isolate* isolate, Zone* zone,
CallDescriptor* call_descriptor, Code::Kind kind,
......@@ -1448,18 +1444,17 @@ class V8_EXPORT_PRIVATE CodeAssemblerState {
DISALLOW_COPY_AND_ASSIGN(CodeAssemblerState);
};
class V8_EXPORT_PRIVATE CodeAssemblerScopedExceptionHandler {
class V8_EXPORT_PRIVATE ScopedExceptionHandler {
public:
CodeAssemblerScopedExceptionHandler(
CodeAssembler* assembler, CodeAssemblerExceptionHandlerLabel* label);
ScopedExceptionHandler(CodeAssembler* assembler,
CodeAssemblerExceptionHandlerLabel* label);
// Use this constructor for compatability/ports of old CSA code only. New code
// should use the CodeAssemblerExceptionHandlerLabel version.
CodeAssemblerScopedExceptionHandler(
CodeAssembler* assembler, CodeAssemblerLabel* label,
TypedCodeAssemblerVariable<Object>* exception);
ScopedExceptionHandler(CodeAssembler* assembler, CodeAssemblerLabel* label,
TypedCodeAssemblerVariable<Object>* exception);
~CodeAssemblerScopedExceptionHandler();
~ScopedExceptionHandler();
private:
bool has_handler_;
......
......@@ -587,8 +587,8 @@ std::string CSAGenerator::PreCallableExceptionPreparation(
catch_name = FreshCatchName();
out() << " compiler::CodeAssemblerExceptionHandlerLabel " << catch_name
<< "__label(&ca_, compiler::CodeAssemblerLabel::kDeferred);\n";
out() << " { compiler::CodeAssemblerScopedExceptionHandler s(&ca_, &"
<< catch_name << "__label);\n";
out() << " { compiler::ScopedExceptionHandler s(&ca_, &" << catch_name
<< "__label);\n";
}
return catch_name;
}
......
......@@ -34,11 +34,6 @@ Node* UndefinedConstant(CodeAssembler* m) {
return m->LoadRoot(RootIndex::kUndefinedValue);
}
TNode<Smi> SmiFromInt32(CodeAssembler* m, TNode<Int32T> value) {
return m->BitcastWordToTaggedSigned(
m->WordShl(m->ChangeInt32ToIntPtr(value), kSmiShiftSize + kSmiTagSize));
}
Node* LoadObjectField(CodeAssembler* m, Node* object, int offset,
MachineType type = MachineType::AnyTagged()) {
return m->Load(type, object, m->IntPtrConstant(offset - kHeapObjectTag));
......@@ -445,128 +440,6 @@ TEST(TestOutOfScopeVariable) {
CHECK(!asm_tester.GenerateCode().is_null());
}
TEST(GotoIfException) {
Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 1;
CodeAssemblerTester asm_tester(isolate, kNumParams);
CodeAssembler m(asm_tester.state());
TNode<Context> context =
m.HeapConstant(Handle<Context>(isolate->native_context()));
TNode<Symbol> to_string_tag =
m.HeapConstant(isolate->factory()->to_string_tag_symbol());
Variable exception(&m, MachineRepresentation::kTagged);
CodeAssemblerLabel exception_handler(&m);
Callable to_string = Builtins::CallableFor(isolate, Builtins::kToString);
TNode<Object> string = m.CallStub(to_string, context, to_string_tag);
m.GotoIfException(string, &exception_handler, &exception);
m.Return(string);
m.Bind(&exception_handler);
m.Return(m.UncheckedCast<Object>(exception.value()));
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
Handle<Object> result = ft.Call().ToHandleChecked();
// Should be a TypeError.
CHECK(result->IsJSObject());
Handle<Object> constructor =
Object::GetPropertyOrElement(isolate, result,
isolate->factory()->constructor_string())
.ToHandleChecked();
CHECK(constructor->SameValue(*isolate->type_error_function()));
}
TEST(GotoIfExceptionMultiple) {
Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 4; // receiver, first, second, third
CodeAssemblerTester asm_tester(isolate, kNumParams);
CodeAssembler m(asm_tester.state());
TNode<Context> context =
m.HeapConstant(Handle<Context>(isolate->native_context()));
Node* first_value = m.Parameter(0);
Node* second_value = m.Parameter(1);
Node* third_value = m.Parameter(2);
CodeAssemblerLabel exception_handler1(&m);
CodeAssemblerLabel exception_handler2(&m);
CodeAssemblerLabel exception_handler3(&m);
Variable return_value(&m, MachineRepresentation::kWord32);
Variable error(&m, MachineRepresentation::kTagged);
return_value.Bind(m.Int32Constant(0));
// try { return ToString(param1) } catch (e) { ... }
Callable to_string = Builtins::CallableFor(isolate, Builtins::kToString);
TNode<Object> string = m.CallStub(to_string, context, first_value);
m.GotoIfException(string, &exception_handler1, &error);
m.Return(string);
// try { ToString(param2); return 7 } catch (e) { ... }
m.Bind(&exception_handler1);
return_value.Bind(m.Int32Constant(7));
error.Bind(UndefinedConstant(&m));
string = m.CallStub(to_string, context, second_value);
m.GotoIfException(string, &exception_handler2, &error);
m.Return(SmiFromInt32(&m, m.UncheckedCast<Int32T>(return_value.value())));
// try { ToString(param3); return 7 & ~2; } catch (e) { return e; }
m.Bind(&exception_handler2);
// Return returnValue & ~2
error.Bind(UndefinedConstant(&m));
string = m.CallStub(to_string, context, third_value);
m.GotoIfException(string, &exception_handler3, &error);
m.Return(SmiFromInt32(
&m, m.UncheckedCast<Int32T>(m.Word32And(
return_value.value(),
m.Word32Xor(m.Int32Constant(2), m.Int32Constant(-1))))));
m.Bind(&exception_handler3);
m.Return(m.UncheckedCast<Object>(error.value()));
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
Handle<Object> result;
// First handler does not throw, returns result of first value.
result = ft.Call(isolate->factory()->undefined_value(),
isolate->factory()->to_string_tag_symbol())
.ToHandleChecked();
CHECK(String::cast(*result).IsOneByteEqualTo(OneByteVector("undefined")));
// First handler returns a number.
result = ft.Call(isolate->factory()->to_string_tag_symbol(),
isolate->factory()->undefined_value())
.ToHandleChecked();
CHECK_EQ(7, Smi::ToInt(*result));
// First handler throws, second handler returns a number.
result = ft.Call(isolate->factory()->to_string_tag_symbol(),
isolate->factory()->to_primitive_symbol())
.ToHandleChecked();
CHECK_EQ(7 & ~2, Smi::ToInt(*result));
// First handler throws, second handler throws, third handler returns thrown
// value.
result = ft.Call(isolate->factory()->to_string_tag_symbol(),
isolate->factory()->to_primitive_symbol(),
isolate->factory()->unscopables_symbol())
.ToHandleChecked();
// Should be a TypeError.
CHECK(result->IsJSObject());
Handle<Object> constructor =
Object::GetPropertyOrElement(isolate, result,
isolate->factory()->constructor_string())
.ToHandleChecked();
CHECK(constructor->SameValue(*isolate->type_error_function()));
}
TEST(ExceptionHandler) {
Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 0;
......@@ -576,7 +449,7 @@ TEST(ExceptionHandler) {
CodeAssembler::TVariable<Object> var(m.SmiConstant(0), &m);
CodeAssemblerLabel exception(&m, {&var}, CodeAssemblerLabel::kDeferred);
{
CodeAssemblerScopedExceptionHandler handler(&m, &exception, &var);
ScopedExceptionHandler handler(&m, &exception, &var);
TNode<Context> context =
m.HeapConstant(Handle<Context>(isolate->native_context()));
m.CallRuntime(Runtime::kThrow, context, m.SmiConstant(2));
......
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