[collections] Port Map constructor to CSA

Bug: v8:5717, v8:6354
Change-Id: I4be80eabcb0f98446e695a2ab1ad5804b7181ac7
Reviewed-on: https://chromium-review.googlesource.com/506818
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45489}
This commit is contained in:
Sathya Gunasekaran 2017-05-23 02:06:51 -07:00 committed by Commit Bot
parent 36f78645a7
commit aca3c14f15
17 changed files with 505 additions and 83 deletions

View File

@ -911,6 +911,7 @@ v8_source_set("v8_builtins_generators") {
"src/builtins/builtins-async-iterator-gen.cc",
"src/builtins/builtins-boolean-gen.cc",
"src/builtins/builtins-call-gen.cc",
"src/builtins/builtins-collections-gen.cc",
"src/builtins/builtins-console-gen.cc",
"src/builtins/builtins-constructor-gen.cc",
"src/builtins/builtins-constructor-gen.h",
@ -928,6 +929,8 @@ v8_source_set("v8_builtins_generators") {
"src/builtins/builtins-internal-gen.cc",
"src/builtins/builtins-interpreter-gen.cc",
"src/builtins/builtins-intl-gen.cc",
"src/builtins/builtins-iterator-gen.cc",
"src/builtins/builtins-iterator-gen.h",
"src/builtins/builtins-math-gen.cc",
"src/builtins/builtins-number-gen.cc",
"src/builtins/builtins-object-gen.cc",

View File

@ -2911,11 +2911,40 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
}
{ // -- M a p
Handle<JSFunction> js_map_fun = InstallFunction(
global, "Map", JS_MAP_TYPE, JSMap::kSize,
isolate->initial_object_prototype(), Builtins::kIllegal);
{
Handle<String> index_string = isolate->factory()->zero_string();
uint32_t field =
StringHasher::MakeArrayIndexHash(0, index_string->length());
index_string->set_hash_field(field);
index_string = isolate->factory()->one_string();
field = StringHasher::MakeArrayIndexHash(1, index_string->length());
index_string->set_hash_field(field);
}
Handle<JSObject> prototype =
factory->NewJSObject(isolate->object_function(), TENURED);
Handle<JSFunction> js_map_fun =
InstallFunction(global, "Map", JS_MAP_TYPE, JSMap::kSize, prototype,
Builtins::kMapConstructor);
InstallWithIntrinsicDefaultProto(isolate, js_map_fun,
Context::JS_MAP_FUN_INDEX);
Handle<SharedFunctionInfo> shared(js_map_fun->shared(), isolate);
shared->SetConstructStub(*isolate->builtins()->JSBuiltinsConstructStub());
shared->set_instance_class_name(isolate->heap()->Map_string());
shared->set_internal_formal_parameter_count(1);
shared->set_length(0);
// Install the "constructor" property on the {prototype}.
JSObject::AddProperty(prototype, factory->constructor_string(), js_map_fun,
DONT_ENUM);
// Install the @@toStringTag property on the {prototype}.
JSObject::AddProperty(
prototype, factory->to_string_tag_symbol(), factory->Map_string(),
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
InstallSpeciesGetter(js_map_fun);
}

View File

@ -0,0 +1,156 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins-constructor-gen.h"
#include "src/builtins/builtins-iterator-gen.h"
#include "src/builtins/builtins-utils-gen.h"
#include "src/code-stub-assembler.h"
namespace v8 {
namespace internal {
using compiler::Node;
class CollectionsBuiltinsAssembler : public CodeStubAssembler {
public:
explicit CollectionsBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
Node* AllocateJSMap(Node* js_map_function);
};
Node* CollectionsBuiltinsAssembler::AllocateJSMap(Node* js_map_function) {
Node* const initial_map = LoadObjectField(
js_map_function, JSFunction::kPrototypeOrInitialMapOffset);
Node* const instance = AllocateJSObjectFromMap(initial_map);
StoreObjectFieldRoot(instance, JSMap::kTableOffset,
Heap::kUndefinedValueRootIndex);
return instance;
}
TF_BUILTIN(MapConstructor, CollectionsBuiltinsAssembler) {
// TODO(gsathya): Don't use arguments adaptor
Node* const iterable = Parameter(Descriptor::kIterable);
Node* const new_target = Parameter(Descriptor::kNewTarget);
Node* const context = Parameter(Descriptor::kContext);
Label if_target_is_undefined(this, Label::kDeferred);
GotoIf(IsUndefined(new_target), &if_target_is_undefined);
Node* const native_context = LoadNativeContext(context);
Node* const js_map_fun =
LoadContextElement(native_context, Context::JS_MAP_FUN_INDEX);
VARIABLE(var_result, MachineRepresentation::kTagged);
Label init(this), exit(this), if_targetisnotmodified(this),
if_targetismodified(this);
Branch(WordEqual(js_map_fun, new_target), &if_targetisnotmodified,
&if_targetismodified);
BIND(&if_targetisnotmodified);
{
Node* const instance = AllocateJSMap(js_map_fun);
var_result.Bind(instance);
Goto(&init);
}
BIND(&if_targetismodified);
{
ConstructorBuiltinsAssembler constructor_assembler(this->state());
Node* const instance = constructor_assembler.EmitFastNewObject(
context, js_map_fun, new_target);
var_result.Bind(instance);
Goto(&init);
}
BIND(&init);
// TODO(gsathya): Remove runtime call once OrderedHashTable is ported.
CallRuntime(Runtime::kMapInitialize, context, var_result.value());
GotoIf(Word32Or(IsUndefined(iterable), IsNull(iterable)), &exit);
Label if_notcallable(this);
// TODO(gsathya): Add fast path for unmodified maps.
Node* const adder = GetProperty(context, var_result.value(),
isolate()->factory()->set_string());
GotoIf(TaggedIsSmi(adder), &if_notcallable);
GotoIfNot(IsCallable(adder), &if_notcallable);
IteratorBuiltinsAssembler iterator_assembler(this->state());
Node* const iterator = iterator_assembler.GetIterator(context, iterable);
GotoIf(IsUndefined(iterator), &exit);
Node* const fast_iterator_result_map =
LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
VARIABLE(var_exception, MachineRepresentation::kTagged, UndefinedConstant());
Label loop(this), if_notobject(this), if_exception(this);
Goto(&loop);
BIND(&loop);
{
Node* const next = iterator_assembler.IteratorStep(
context, iterator, &exit, fast_iterator_result_map);
Node* const next_value = iterator_assembler.IteratorValue(
context, next, fast_iterator_result_map);
GotoIf(TaggedIsSmi(next_value), &if_notobject);
GotoIfNot(IsJSReceiver(next_value), &if_notobject);
Node* const k =
GetProperty(context, next_value, isolate()->factory()->zero_string());
GotoIfException(k, &if_exception, &var_exception);
Node* const v =
GetProperty(context, next_value, isolate()->factory()->one_string());
GotoIfException(v, &if_exception, &var_exception);
Node* add_call = CallJS(CodeFactory::Call(isolate()), context, adder,
var_result.value(), k, v);
GotoIfException(add_call, &if_exception, &var_exception);
Goto(&loop);
BIND(&if_notobject);
{
Node* const exception = MakeTypeError(
MessageTemplate::kIteratorValueNotAnObject, context, next_value);
var_exception.Bind(exception);
Goto(&if_exception);
}
}
BIND(&if_exception);
{
iterator_assembler.IteratorClose(context, iterator, var_exception.value());
}
BIND(&if_notcallable);
{
Node* const message_id = SmiConstant(MessageTemplate::kPropertyNotFunction);
Node* const receiver_str = HeapConstant(isolate()->factory()->set_string());
CallRuntime(Runtime::kThrowTypeError, context, message_id, adder,
receiver_str, var_result.value());
Unreachable();
}
BIND(&if_target_is_undefined);
{
Node* const message_id =
SmiConstant(MessageTemplate::kConstructorNotFunction);
CallRuntime(Runtime::kThrowTypeError, context, message_id, new_target);
Unreachable();
}
BIND(&exit);
Return(var_result.value());
}
} // namespace internal
} // namespace v8

View File

@ -538,6 +538,9 @@ namespace internal {
TFH(LoadGlobalICInsideTypeofTrampoline, LOAD_GLOBAL_IC, kNoExtraICState, \
LoadGlobal) \
\
/* Map */ \
TFJ(MapConstructor, 1, kIterable) \
\
/* Math */ \
/* ES6 #sec-math.abs */ \
TFJ(MathAbs, 1, kX) \
@ -1041,6 +1044,8 @@ namespace internal {
#define BUILTIN_EXCEPTION_CAUGHT_PREDICTION_LIST(V) V(PromiseHandleReject)
#define BUILTIN_EXCEPTION_UNCAUGHT_PREDICTION_LIST(V) V(MapConstructor)
#define IGNORE_BUILTIN(...)
#define BUILTIN_LIST_ALL(V) BUILTIN_LIST(V, V, V, V, V, V, V, V)

View File

@ -0,0 +1,164 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins-iterator-gen.h"
namespace v8 {
namespace internal {
using compiler::Node;
Node* IteratorBuiltinsAssembler::GetIterator(Node* context, Node* object) {
Node* method = GetProperty(context, object, factory()->iterator_symbol());
Callable callable = CodeFactory::Call(isolate());
Node* iterator = CallJS(callable, context, method, object);
Label done(this), if_notobject(this, Label::kDeferred);
GotoIf(TaggedIsSmi(iterator), &if_notobject);
Branch(IsJSReceiver(iterator), &done, &if_notobject);
BIND(&if_notobject);
{
CallRuntime(Runtime::kThrowTypeError, context,
SmiConstant(MessageTemplate::kNotAnIterator), iterator);
Unreachable();
}
BIND(&done);
return iterator;
}
Node* IteratorBuiltinsAssembler::IteratorStep(Node* context, Node* iterator,
Label* if_done,
Node* fast_iterator_result_map) {
DCHECK_NOT_NULL(if_done);
// IteratorNext
Node* next_method = GetProperty(context, iterator, factory()->next_string());
// 1. a. Let result be ? Invoke(iterator, "next", « »).
Callable callable = CodeFactory::Call(isolate());
Node* result = CallJS(callable, context, next_method, iterator);
// 3. If Type(result) is not Object, throw a TypeError exception.
Label if_notobject(this, Label::kDeferred), return_result(this);
GotoIf(TaggedIsSmi(result), &if_notobject);
GotoIfNot(IsJSReceiver(result), &if_notobject);
Label if_generic(this);
VARIABLE(var_done, MachineRepresentation::kTagged);
if (fast_iterator_result_map != nullptr) {
// 4. Return result.
Node* map = LoadMap(result);
GotoIfNot(WordEqual(map, fast_iterator_result_map), &if_generic);
// IteratorComplete
// 2. Return ToBoolean(? Get(iterResult, "done")).
Node* done = LoadObjectField(result, JSIteratorResult::kDoneOffset);
CSA_ASSERT(this, IsBoolean(done));
var_done.Bind(done);
Goto(&return_result);
} else {
Goto(&if_generic);
}
BIND(&if_generic);
{
// IteratorComplete
// 2. Return ToBoolean(? Get(iterResult, "done")).
Node* done = GetProperty(context, result, factory()->done_string());
var_done.Bind(done);
Label to_boolean(this, Label::kDeferred);
GotoIf(TaggedIsSmi(done), &to_boolean);
Branch(IsBoolean(done), &return_result, &to_boolean);
BIND(&to_boolean);
var_done.Bind(CallStub(CodeFactory::ToBoolean(isolate()), context, done));
Goto(&return_result);
}
BIND(&if_notobject);
{
CallRuntime(Runtime::kThrowIteratorResultNotAnObject, context, result);
Goto(if_done);
}
BIND(&return_result);
GotoIf(IsTrue(var_done.value()), if_done);
return result;
}
Node* IteratorBuiltinsAssembler::IteratorValue(Node* context, Node* result,
Node* fast_iterator_result_map) {
CSA_ASSERT(this, IsJSReceiver(result));
Label exit(this), if_generic(this);
VARIABLE(var_value, MachineRepresentation::kTagged);
if (fast_iterator_result_map != nullptr) {
Node* map = LoadMap(result);
GotoIfNot(WordEqual(map, fast_iterator_result_map), &if_generic);
var_value.Bind(LoadObjectField(result, JSIteratorResult::kValueOffset));
Goto(&exit);
} else {
Goto(&if_generic);
}
BIND(&if_generic);
{
Node* value = GetProperty(context, result, factory()->value_string());
var_value.Bind(value);
Goto(&exit);
}
BIND(&exit);
return var_value.value();
}
void IteratorBuiltinsAssembler::IteratorClose(Node* context, Node* iterator,
Node* exception) {
CSA_ASSERT(this, IsJSReceiver(iterator));
VARIABLE(var_iter_exception, MachineRepresentation::kTagged,
UndefinedConstant());
Label rethrow_exception(this);
Node* method = GetProperty(context, iterator, factory()->return_string());
GotoIf(Word32Or(IsUndefined(method), IsNull(method)), &rethrow_exception);
Label if_iter_exception(this), if_notobject(this);
Node* inner_result =
CallJS(CodeFactory::Call(isolate()), context, method, iterator);
GotoIfException(inner_result, &if_iter_exception, &var_iter_exception);
GotoIfNot(IsUndefined(exception), &rethrow_exception);
GotoIf(TaggedIsSmi(inner_result), &if_notobject);
Branch(IsJSReceiver(inner_result), &rethrow_exception, &if_notobject);
BIND(&if_notobject);
{
CallRuntime(Runtime::kThrowIteratorResultNotAnObject, context,
inner_result);
Unreachable();
}
BIND(&if_iter_exception);
{
GotoIfNot(IsUndefined(exception), &rethrow_exception);
CallRuntime(Runtime::kReThrow, context, var_iter_exception.value());
Unreachable();
}
BIND(&rethrow_exception);
{
CallRuntime(Runtime::kReThrow, context, exception);
Unreachable();
}
}
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,41 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/code-stub-assembler.h"
namespace v8 {
namespace internal {
using compiler::Node;
class IteratorBuiltinsAssembler : public CodeStubAssembler {
public:
explicit IteratorBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
// https://tc39.github.io/ecma262/#sec-getiterator --- never used for
// @@asyncIterator.
Node* GetIterator(Node* context, Node* object);
// https://tc39.github.io/ecma262/#sec-iteratorstep
// Returns `false` if the iterator is done, otherwise returns an
// iterator result.
// `fast_iterator_result_map` refers to the map for the JSIteratorResult
// object, loaded from the native context.
Node* IteratorStep(Node* context, Node* iterator, Label* if_done,
Node* fast_iterator_result_map = nullptr);
// https://tc39.github.io/ecma262/#sec-iteratorvalue
// Return the `value` field from an iterator.
// `fast_iterator_result_map` refers to the map for the JSIteratorResult
// object, loaded from the native context.
Node* IteratorValue(Node* context, Node* result,
Node* fast_iterator_result_map = nullptr);
// https://tc39.github.io/ecma262/#sec-iteratorclose
void IteratorClose(Node* context, Node* iterator, Node* exception);
};
} // namespace internal
} // namespace v8

View File

@ -179,6 +179,7 @@ void SetupIsolateDelegate::SetupBuiltinsInternal(Isolate* isolate) {
->set_is_promise_rejection(true);
BUILTIN_PROMISE_REJECTION_PREDICTION_LIST(SET_PROMISE_REJECTION_PREDICTION)
BUILTIN_EXCEPTION_UNCAUGHT_PREDICTION_LIST(SET_PROMISE_REJECTION_PREDICTION)
#undef SET_PROMISE_REJECTION_PREDICTION
#define SET_EXCEPTION_CAUGHT_PREDICTION(Name) \
@ -186,6 +187,7 @@ void SetupIsolateDelegate::SetupBuiltinsInternal(Isolate* isolate) {
->set_is_exception_caught(true);
BUILTIN_EXCEPTION_CAUGHT_PREDICTION_LIST(SET_EXCEPTION_CAUGHT_PREDICTION)
BUILTIN_EXCEPTION_UNCAUGHT_PREDICTION_LIST(SET_EXCEPTION_CAUGHT_PREDICTION)
#undef SET_EXCEPTION_CAUGHT_PREDICTION
#define SET_CODE_NON_TAGGED_PARAMS(Name) \

View File

@ -3714,7 +3714,13 @@ void HPhi::SimplifyConstantInputs() {
SetOperandAt(i, operand->BooleanValue() ? graph->GetConstant1()
: graph->GetConstant0());
} else if (operand->ImmortalImmovable()) {
SetOperandAt(i, graph->GetConstant0());
if (operand->HasStringValue() &&
operand->EqualsUnique(
Unique<String>(isolate()->factory()->one_string()))) {
SetOperandAt(i, graph->GetConstant1());
} else {
SetOperandAt(i, graph->GetConstant0());
}
}
}
// Overwrite observed input representations because they are likely Tagged.

View File

@ -341,6 +341,8 @@ bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
V(ForInPrepare) \
V(Call) \
V(MaxSmi) \
V(NewObject) \
V(FinalizeInstanceSize) \
V(HasInPrototypeChain)
#define CASE(Name) \
@ -525,6 +527,8 @@ bool BuiltinHasNoSideEffect(Builtins::Name id) {
case Builtins::kDatePrototypeToJson:
case Builtins::kDatePrototypeToPrimitive:
case Builtins::kDatePrototypeValueOf:
// Map builtins.
case Builtins::kMapConstructor:
// Math builtins.
case Builtins::kMathAbs:
case Builtins::kMathAcos:

View File

@ -125,6 +125,7 @@
V(object_string, "object") \
V(Object_string, "Object") \
V(ok, "ok") \
V(one_string, "1") \
V(ownKeys_string, "ownKeys") \
V(position_string, "position") \
V(preventExtensions_string, "preventExtensions") \
@ -190,7 +191,8 @@
V(weekday_string, "weekday") \
V(will_handle_string, "willHandle") \
V(writable_string, "writable") \
V(year_string, "year")
V(year_string, "year") \
V(zero_string, "0")
#define PRIVATE_SYMBOL_LIST(V) \
V(array_iteration_kind_symbol) \

View File

@ -1376,18 +1376,7 @@ HandlerTable::CatchPrediction PredictException(JavaScriptFrame* frame) {
for (const FrameSummary& summary : summaries) {
Handle<AbstractCode> code = summary.AsJavaScript().abstract_code();
if (code->IsCode() && code->kind() == AbstractCode::BUILTIN) {
if (code->GetCode()->is_promise_rejection()) {
return HandlerTable::PROMISE;
}
// This the exception throw in PromiseHandle which doesn't
// cause a promise rejection.
if (code->GetCode()->is_exception_caught()) {
return HandlerTable::CAUGHT;
}
// The built-in must be marked with an exception prediction.
UNREACHABLE();
return code->GetCode()->GetBuiltinCatchPrediction();
}
if (code->kind() == AbstractCode::OPTIMIZED_FUNCTION) {
@ -1411,6 +1400,23 @@ HandlerTable::CatchPrediction PredictException(JavaScriptFrame* frame) {
}
return HandlerTable::UNCAUGHT;
}
Isolate::CatchType ToCatchType(HandlerTable::CatchPrediction prediction) {
switch (prediction) {
case HandlerTable::UNCAUGHT:
return Isolate::NOT_CAUGHT;
case HandlerTable::CAUGHT:
return Isolate::CAUGHT_BY_JAVASCRIPT;
case HandlerTable::PROMISE:
return Isolate::CAUGHT_BY_PROMISE;
case HandlerTable::DESUGARING:
return Isolate::CAUGHT_BY_DESUGARING;
case HandlerTable::ASYNC_AWAIT:
return Isolate::CAUGHT_BY_ASYNC_AWAIT;
default:
UNREACHABLE();
}
}
} // anonymous namespace
Isolate::CatchType Isolate::PredictExceptionCatcher() {
@ -1440,37 +1446,18 @@ Isolate::CatchType Isolate::PredictExceptionCatcher() {
case StackFrame::INTERPRETED:
case StackFrame::BUILTIN: {
JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame);
HandlerTable::CatchPrediction prediction = PredictException(js_frame);
switch (prediction) {
case HandlerTable::UNCAUGHT:
break;
case HandlerTable::CAUGHT:
return CAUGHT_BY_JAVASCRIPT;
case HandlerTable::PROMISE:
return CAUGHT_BY_PROMISE;
case HandlerTable::DESUGARING:
return CAUGHT_BY_DESUGARING;
case HandlerTable::ASYNC_AWAIT:
return CAUGHT_BY_ASYNC_AWAIT;
}
Isolate::CatchType prediction = ToCatchType(PredictException(js_frame));
if (prediction == NOT_CAUGHT) break;
return prediction;
} break;
case StackFrame::STUB: {
Handle<Code> code(frame->LookupCode());
if (code->kind() == Code::BUILTIN && code->is_turbofanned() &&
code->handler_table()->length()) {
if (code->is_promise_rejection()) {
return CAUGHT_BY_PROMISE;
}
// This the exception throw in PromiseHandle which doesn't
// cause a promise rejection.
if (code->is_exception_caught()) {
return CAUGHT_BY_JAVASCRIPT;
}
// The built-in must be marked with an exception prediction.
UNREACHABLE();
CatchType prediction = ToCatchType(code->GetBuiltinCatchPrediction());
if (prediction == NOT_CAUGHT) break;
return prediction;
}
} break;

View File

@ -275,29 +275,6 @@ utils.InstallFunctions(GlobalSet.prototype, DONT_ENUM, [
// -------------------------------------------------------------------
// Harmony Map
function MapConstructor(iterable) {
if (IS_UNDEFINED(new.target)) {
throw %make_type_error(kConstructorNotFunction, "Map");
}
%_MapInitialize(this);
if (!IS_NULL_OR_UNDEFINED(iterable)) {
var adder = this.set;
if (!IS_CALLABLE(adder)) {
throw %make_type_error(kPropertyNotFunction, adder, 'set', this);
}
for (var nextItem of iterable) {
if (!IS_RECEIVER(nextItem)) {
throw %make_type_error(kIteratorValueNotAnObject, nextItem);
}
%_Call(adder, this, nextItem[0], nextItem[1]);
}
}
}
function MapGet(key) {
if (!IS_MAP(this)) {
throw %make_type_error(kIncompatibleMethodReceiver,
@ -432,13 +409,6 @@ function MapForEach(f, receiver) {
// -------------------------------------------------------------------
%SetCode(GlobalMap, MapConstructor);
%FunctionSetLength(GlobalMap, 0);
%FunctionSetPrototype(GlobalMap, new GlobalObject());
%AddNamedProperty(GlobalMap.prototype, "constructor", GlobalMap, DONT_ENUM);
%AddNamedProperty(
GlobalMap.prototype, toStringTagSymbol, "Map", DONT_ENUM | READ_ONLY);
%FunctionSetLength(MapForEach, 1);
// Set up the non-enumerable functions on the Map prototype object.

View File

@ -4794,6 +4794,26 @@ inline void Code::set_is_exception_caught(bool value) {
WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated);
}
inline HandlerTable::CatchPrediction Code::GetBuiltinCatchPrediction() {
// An exception is uncaught if both is_promise_rejection and
// is_exception_caught bits are set.
if (is_promise_rejection() && is_exception_caught()) {
return HandlerTable::UNCAUGHT;
}
if (is_promise_rejection()) {
return HandlerTable::PROMISE;
}
// This the exception throw in PromiseHandle which doesn't
// cause a promise rejection.
if (is_exception_caught()) {
return HandlerTable::CAUGHT;
}
UNREACHABLE();
}
bool Code::has_deoptimization_support() {
DCHECK_EQ(FUNCTION, kind());
unsigned flags = READ_UINT32_FIELD(this, kFullCodeFlags);

View File

@ -3892,14 +3892,16 @@ class Code: public HeapObject {
inline bool deopt_already_counted();
inline void set_deopt_already_counted(bool flag);
// [is_promise_rejection]: For kind BUILTIN tells whether the exception
// thrown by the code will lead to promise rejection.
inline bool is_promise_rejection();
// [is_promise_rejection]: For kind BUILTIN tells whether the
// exception thrown by the code will lead to promise rejection or
// uncaught if both this and is_exception_caught is set.
// Use GetBuiltinCatchPrediction to access this.
inline void set_is_promise_rejection(bool flag);
// [is_exception_caught]: For kind BUILTIN tells whether the exception
// thrown by the code will be caught internally.
inline bool is_exception_caught();
// [is_exception_caught]: For kind BUILTIN tells whether the
// exception thrown by the code will be caught internally or
// uncaught if both this and is_promise_rejection is set.
// Use GetBuiltinCatchPrediction to access this.
inline void set_is_exception_caught(bool flag);
// [constant_pool]: The constant pool for this function.
@ -4080,6 +4082,7 @@ class Code: public HeapObject {
void PrintDeoptLocation(FILE* out, Address pc);
bool CanDeoptAt(Address pc);
inline HandlerTable::CatchPrediction GetBuiltinCatchPrediction();
#ifdef VERIFY_HEAP
void VerifyEmbeddedObjectsDependency();
#endif
@ -4231,6 +4234,9 @@ class Code: public HeapObject {
// Code aging -- platform-specific
static void PatchPlatformCodeAge(Isolate* isolate, byte* sequence, Age age);
bool is_promise_rejection();
bool is_exception_caught();
DISALLOW_IMPLICIT_CONSTRUCTORS(Code);
};

View File

@ -180,6 +180,7 @@
'builtins/builtins-async-iterator-gen.cc',
'builtins/builtins-boolean-gen.cc',
'builtins/builtins-call-gen.cc',
'builtins/builtins-collections-gen.cc',
'builtins/builtins-console-gen.cc',
'builtins/builtins-constructor-gen.cc',
'builtins/builtins-constructor-gen.h',
@ -197,6 +198,8 @@
'builtins/builtins-internal-gen.cc',
'builtins/builtins-interpreter-gen.cc',
'builtins/builtins-intl-gen.cc',
'builtins/builtins-iterator-gen.h',
'builtins/builtins-iterator-gen.cc',
'builtins/builtins-math-gen.cc',
'builtins/builtins-number-gen.cc',
'builtins/builtins-object-gen.cc',

View File

@ -6668,13 +6668,10 @@ TEST(BuiltinsExceptionPrediction) {
if (i::HandlerTable::cast(builtin->handler_table())->length() == 0)
continue;
if (builtin->is_promise_rejection() || builtin->is_exception_caught())
continue;
if (whitelist.find(i) != whitelist.end()) continue;
fail = true;
i::PrintF("%s is missing exception predictions.\n", builtins->name(i));
auto prediction = builtin->GetBuiltinCatchPrediction();
USE(prediction);
}
CHECK(!fail);
}

View File

@ -0,0 +1,27 @@
// Copyright (C) 2017 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 23.1.1.1
description: >
The correct error is thrown `Map.prototype.set` throws an error and
the IteratorClose throws an error.
features: [Symbol.iterator]
---*/
var count = 0;
var iterable = {};
iterable[Symbol.iterator] = function() {
return {
next: function() {
return { value: [], done: false };
},
return: function() {
throw new TypeError('ignore');
}
};
};
Map.prototype.set = function() { throw new Test262Error(); }
assert.throws(Test262Error, function() {
new Map(iterable);
});