[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:
parent
36f78645a7
commit
aca3c14f15
3
BUILD.gn
3
BUILD.gn
@ -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",
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
156
src/builtins/builtins-collections-gen.cc
Normal file
156
src/builtins/builtins-collections-gen.cc
Normal 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
|
@ -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)
|
||||
|
164
src/builtins/builtins-iterator-gen.cc
Normal file
164
src/builtins/builtins-iterator-gen.cc
Normal 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
|
41
src/builtins/builtins-iterator-gen.h
Normal file
41
src/builtins/builtins-iterator-gen.h
Normal 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
|
@ -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) \
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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) \
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
Loading…
Reference in New Issue
Block a user