Commit c59fbf13 authored by Joshua Litt's avatar Joshua Litt Committed by Commit Bot

[promises] Port promiseAll ResolveElementClosure to Torque.

Bug: v8:9838
Change-Id: Ib7af793218d005883b0ab5423714fdf43664cbc4
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1972611
Commit-Queue: Joshua Litt <joshualitt@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65818}
parent dabc6eb5
......@@ -826,9 +826,15 @@ template("asm_to_inline_asm") {
assert(emit_builtins_as_inline_asm)
script = "tools/snapshot/asm_to_inline_asm.py"
deps = [ ":run_mksnapshot_" + name ]
sources = [ "$target_gen_dir/embedded${suffix}.S" ]
outputs = [ "$target_gen_dir/embedded${suffix}.cc" ]
deps = [
":run_mksnapshot_" + name,
]
sources = [
"$target_gen_dir/embedded${suffix}.S",
]
outputs = [
"$target_gen_dir/embedded${suffix}.cc",
]
args = invoker.args
args += [
rebase_path("$target_gen_dir/embedded${suffix}.S", root_build_dir),
......@@ -842,7 +848,9 @@ if (is_android && enable_java_templates) {
if (v8_use_external_startup_data) {
# We don't support side-by-side snapshots on Android within Chromium.
assert(!v8_use_multi_snapshots)
deps = [ "//v8" ]
deps = [
"//v8",
]
renaming_sources = [ "$root_out_dir/snapshot_blob.bin" ]
if (current_cpu == "arm" || current_cpu == "x86" ||
current_cpu == "mipsel") {
......@@ -926,12 +934,16 @@ action("postmortem-metadata") {
"$target_gen_dir/torque-generated/instance-types-tq.h",
]
outputs = [ "$target_gen_dir/debug-support.cc" ]
outputs = [
"$target_gen_dir/debug-support.cc",
]
args = rebase_path(outputs, root_build_dir) +
rebase_path(sources, root_build_dir)
deps = [ ":run_torque" ]
deps = [
":run_torque",
]
}
torque_files = [
......@@ -975,6 +987,7 @@ torque_files = [
"src/builtins/object-fromentries.tq",
"src/builtins/object.tq",
"src/builtins/promise-abstract-operations.tq",
"src/builtins/promise-all-element-closure.tq",
"src/builtins/promise-constructor.tq",
"src/builtins/promise-finally.tq",
"src/builtins/promise-race.tq",
......@@ -1103,7 +1116,9 @@ action("run_torque") {
"test/cctest/:*",
]
deps = [ ":torque($v8_generator_toolchain)" ]
deps = [
":torque($v8_generator_toolchain)",
]
script = "tools/run.py"
......@@ -1152,7 +1167,9 @@ action("run_torque") {
group("v8_maybe_icu") {
if (v8_enable_i18n_support) {
public_deps = [ "//third_party/icu" ]
public_deps = [
"//third_party/icu",
]
}
}
......@@ -1164,7 +1181,9 @@ v8_source_set("torque_generated_initializers") {
":run_torque",
]
public_deps = [ ":v8_maybe_icu" ]
public_deps = [
":v8_maybe_icu",
]
sources = [
"$target_gen_dir/torque-generated/csa-types-tq.h",
......@@ -1192,7 +1211,9 @@ v8_source_set("torque_generated_definitions") {
":run_torque",
]
public_deps = [ ":v8_maybe_icu" ]
public_deps = [
":v8_maybe_icu",
]
sources = [
"$target_gen_dir/torque-generated/class-definitions-tq.cc",
......@@ -1206,8 +1227,12 @@ v8_source_set("torque_generated_definitions") {
action("generate_bytecode_builtins_list") {
script = "tools/run.py"
outputs = [ "$target_gen_dir/builtins-generated/bytecodes-builtins-list.h" ]
deps = [ ":bytecode_builtins_list_generator($v8_generator_toolchain)" ]
outputs = [
"$target_gen_dir/builtins-generated/bytecodes-builtins-list.h",
]
deps = [
":bytecode_builtins_list_generator($v8_generator_toolchain)",
]
args = [
"./" + rebase_path(
get_label_info(
......@@ -1239,7 +1264,9 @@ template("run_mksnapshot") {
action("run_mksnapshot_" + name) {
visibility = [ ":*" ] # Only targets in this file can depend on this.
deps = [ ":mksnapshot($v8_snapshot_toolchain)" ]
deps = [
":mksnapshot($v8_snapshot_toolchain)",
]
script = "tools/run.py"
......@@ -1370,7 +1397,9 @@ if (v8_use_multi_snapshots) {
action("v8_dump_build_config") {
script = "tools/testrunner/utils/dump_build_config.py"
outputs = [ "$root_out_dir/v8_build_config.json" ]
outputs = [
"$root_out_dir/v8_build_config.json",
]
is_gcov_coverage = v8_code_coverage && !is_clang
is_full_debug = v8_enable_debugging_features && !v8_optimized_debug
args = [
......@@ -1424,7 +1453,9 @@ v8_source_set("v8_snapshot") {
# Do not publicize any header to remove build dependency.
public = []
sources = [ "src/init/setup-isolate-deserialize.cc" ]
sources = [
"src/init/setup-isolate-deserialize.cc",
]
if (emit_builtins_as_inline_asm) {
deps += [ ":asm_to_inline_asm_default" ]
sources += [ "$target_gen_dir/embedded.cc" ]
......@@ -1464,7 +1495,9 @@ v8_source_set("v8_initializers") {
"test/cctest:*",
]
deps = [ ":torque_generated_initializers" ]
deps = [
":torque_generated_initializers",
]
sources = [
### gcmole(all) ###
......@@ -1587,14 +1620,18 @@ v8_source_set("v8_initializers") {
v8_source_set("v8_init") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
deps = [ ":v8_initializers" ]
deps = [
":v8_initializers",
]
sources = [
### gcmole(all) ###
"src/init/setup-isolate-full.cc",
]
public_deps = [ ":v8_maybe_icu" ]
public_deps = [
":v8_maybe_icu",
]
configs = [ ":internal_config" ]
}
......@@ -1631,7 +1668,9 @@ v8_header_set("v8_headers") {
"include/v8-wasm-trap-handler-win.h",
]
deps = [ ":v8_version" ]
deps = [
":v8_version",
]
}
# This is split out to share basic headers with Torque.
......@@ -1639,9 +1678,13 @@ v8_header_set("v8_shared_internal_headers") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
configs = [ ":internal_config" ]
sources = [ "src/common/globals.h" ]
sources = [
"src/common/globals.h",
]
deps = [ ":v8_headers" ]
deps = [
":v8_headers",
]
}
v8_compiler_sources = [
......@@ -1922,9 +1965,13 @@ v8_source_set("v8_compiler") {
group("v8_compiler_for_mksnapshot") {
if (is_debug && !v8_optimized_debug && v8_enable_fast_mksnapshot) {
deps = [ ":v8_compiler_opt" ]
deps = [
":v8_compiler_opt",
]
} else {
deps = [ ":v8_compiler" ]
deps = [
":v8_compiler",
]
}
}
......@@ -3379,9 +3426,13 @@ v8_source_set("torque_base") {
"src/torque/utils.h",
]
deps = [ ":v8_shared_internal_headers" ]
deps = [
":v8_shared_internal_headers",
]
public_deps = [ ":v8_libbase" ]
public_deps = [
":v8_libbase",
]
# The use of exceptions for Torque in violation of the Chromium style-guide
# is justified by the fact that it is only used from the non-essential
......@@ -3424,7 +3475,9 @@ v8_source_set("torque_ls_base") {
"src/torque/ls/message.h",
]
public_deps = [ ":torque_base" ]
public_deps = [
":torque_base",
]
# The use of exceptions for Torque in violation of the Chromium style-guide
# is justified by the fact that it is only used from the non-essential
......@@ -3525,7 +3578,9 @@ v8_component("v8_libbase") {
public_configs = [ ":libbase_config" ]
deps = [ ":v8_headers" ]
deps = [
":v8_headers",
]
public_deps = []
......@@ -3711,7 +3766,9 @@ v8_source_set("v8_libsampler") {
public_configs = [ ":libsampler_config" ]
deps = [ ":v8_libbase" ]
deps = [
":v8_libbase",
]
}
v8_source_set("fuzzer_support") {
......@@ -3724,7 +3781,9 @@ v8_source_set("fuzzer_support") {
configs = [ ":internal_config_base" ]
deps = [ ":v8" ]
deps = [
":v8",
]
public_deps = [
":v8_libbase",
......@@ -3846,7 +3905,9 @@ if (current_toolchain == v8_snapshot_toolchain) {
v8_executable("torque") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
sources = [ "src/torque/torque.cc" ]
sources = [
"src/torque/torque.cc",
]
deps = [
":torque_base",
......@@ -3876,7 +3937,9 @@ if (current_toolchain == v8_snapshot_toolchain) {
v8_executable("torque-language-server") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
sources = [ "src/torque/ls/torque-language-server.cc" ]
sources = [
"src/torque/ls/torque-language-server.cc",
]
deps = [
":torque_base",
......@@ -3908,7 +3971,9 @@ if (v8_enable_i18n_support) {
v8_executable("gen-regexp-special-case") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
sources = [ "src/regexp/gen-regexp-special-case.cc" ]
sources = [
"src/regexp/gen-regexp-special-case.cc",
]
deps = [
":v8_libbase",
......@@ -3925,11 +3990,15 @@ if (v8_enable_i18n_support) {
script = "tools/run.py"
deps = [ ":gen-regexp-special-case($v8_generator_toolchain)" ]
deps = [
":gen-regexp-special-case($v8_generator_toolchain)",
]
output_file = "$target_gen_dir/src/regexp/special-case.cc"
outputs = [ output_file ]
outputs = [
output_file,
]
args = [
"./" + rebase_path(
......@@ -3975,13 +4044,17 @@ group("gn_all") {
}
group("v8_python_base") {
data = [ ".vpython" ]
data = [
".vpython",
]
}
group("v8_clusterfuzz") {
testonly = true
deps = [ ":d8" ]
deps = [
":d8",
]
if (v8_multi_arch_build) {
deps += [
......@@ -3997,7 +4070,9 @@ group("v8_clusterfuzz") {
group("v8_archive") {
testonly = true
deps = [ ":d8" ]
deps = [
":d8",
]
if (!is_win) {
# On windows, cctest doesn't link with v8_static_library.
......@@ -4040,7 +4115,9 @@ group("v8_fuzzers") {
if (is_component_build) {
v8_component("v8") {
sources = [ "src/utils/v8dll-main.cc" ]
sources = [
"src/utils/v8dll-main.cc",
]
public_deps = [
":v8_base",
......@@ -4055,7 +4132,9 @@ if (is_component_build) {
v8_component("v8_for_testing") {
testonly = true
sources = [ "src/utils/v8dll-main.cc" ]
sources = [
"src/utils/v8dll-main.cc",
]
public_deps = [
":torque_base",
......@@ -4144,7 +4223,9 @@ v8_executable("d8") {
}
v8_executable("v8_hello_world") {
sources = [ "samples/hello-world.cc" ]
sources = [
"samples/hello-world.cc",
]
configs = [
# Note: don't use :internal_config here because this target will get
......@@ -4162,7 +4243,9 @@ v8_executable("v8_hello_world") {
}
v8_executable("v8_sample_process") {
sources = [ "samples/process.cc" ]
sources = [
"samples/process.cc",
]
configs = [
# Note: don't use :internal_config here because this target will get
......@@ -4181,7 +4264,9 @@ v8_executable("v8_sample_process") {
if (want_v8_shell) {
v8_executable("v8_shell") {
sources = [ "samples/shell.cc" ]
sources = [
"samples/shell.cc",
]
configs = [
# Note: don't use :internal_config here because this target will get
......@@ -4208,16 +4293,22 @@ template("v8_fuzzer") {
"//build/win:default_exe_manifest",
]
sources = [ "test/fuzzer/fuzzer.cc" ]
sources = [
"test/fuzzer/fuzzer.cc",
]
configs = [ ":external_config" ]
}
}
v8_source_set("json_fuzzer") {
sources = [ "test/fuzzer/json.cc" ]
sources = [
"test/fuzzer/json.cc",
]
deps = [ ":fuzzer_support" ]
deps = [
":fuzzer_support",
]
configs = [
":external_config",
......@@ -4229,9 +4320,13 @@ v8_fuzzer("json_fuzzer") {
}
v8_source_set("multi_return_fuzzer") {
sources = [ "test/fuzzer/multi-return.cc" ]
sources = [
"test/fuzzer/multi-return.cc",
]
deps = [ ":fuzzer_support" ]
deps = [
":fuzzer_support",
]
configs = [
":external_config",
......@@ -4243,9 +4338,13 @@ v8_fuzzer("multi_return_fuzzer") {
}
v8_source_set("parser_fuzzer") {
sources = [ "test/fuzzer/parser.cc" ]
sources = [
"test/fuzzer/parser.cc",
]
deps = [ ":fuzzer_support" ]
deps = [
":fuzzer_support",
]
configs = [
":external_config",
......@@ -4262,7 +4361,9 @@ v8_source_set("regexp_builtins_fuzzer") {
"test/fuzzer/regexp_builtins/mjsunit.js.h",
]
deps = [ ":fuzzer_support" ]
deps = [
":fuzzer_support",
]
configs = [
":external_config",
......@@ -4274,9 +4375,13 @@ v8_fuzzer("regexp_builtins_fuzzer") {
}
v8_source_set("regexp_fuzzer") {
sources = [ "test/fuzzer/regexp.cc" ]
sources = [
"test/fuzzer/regexp.cc",
]
deps = [ ":fuzzer_support" ]
deps = [
":fuzzer_support",
]
configs = [
":external_config",
......@@ -4298,7 +4403,9 @@ v8_source_set("wasm_module_runner") {
":run_torque",
]
public_deps = [ ":v8_maybe_icu" ]
public_deps = [
":v8_maybe_icu",
]
configs = [
":external_config",
......@@ -4307,7 +4414,9 @@ v8_source_set("wasm_module_runner") {
}
v8_source_set("wasm_fuzzer") {
sources = [ "test/fuzzer/wasm.cc" ]
sources = [
"test/fuzzer/wasm.cc",
]
deps = [
":fuzzer_support",
......@@ -4325,7 +4434,9 @@ v8_fuzzer("wasm_fuzzer") {
}
v8_source_set("wasm_async_fuzzer") {
sources = [ "test/fuzzer/wasm-async.cc" ]
sources = [
"test/fuzzer/wasm-async.cc",
]
deps = [
":fuzzer_support",
......@@ -4374,7 +4485,9 @@ v8_source_set("lib_wasm_fuzzer_common") {
":run_torque",
]
public_deps = [ ":v8_maybe_icu" ]
public_deps = [
":v8_maybe_icu",
]
configs = [
":external_config",
......@@ -4499,7 +4612,9 @@ if (!build_with_chromium && v8_use_perfetto) {
# This target should be used only by the protoc compiler and by test targets.
source_set("protobuf_full") {
deps = [ ":protobuf_lite" ]
deps = [
":protobuf_lite",
]
sources = [
"third_party/protobuf/src/google/protobuf/any.cc",
"third_party/protobuf/src/google/protobuf/any.pb.cc",
......@@ -4569,7 +4684,9 @@ if (!build_with_chromium && v8_use_perfetto) {
if (current_toolchain == host_toolchain) {
source_set("protoc_lib") {
deps = [ ":protobuf_full" ]
deps = [
":protobuf_full",
]
sources = [
"third_party/protobuf/src/google/protobuf/compiler/code_generator.cc",
"third_party/protobuf/src/google/protobuf/compiler/command_line_interface.cc",
......@@ -4608,7 +4725,9 @@ if (!build_with_chromium && v8_use_perfetto) {
":protoc_lib",
"//build/win:default_exe_manifest",
]
sources = [ "src/protobuf/protobuf-compiler-main.cc" ]
sources = [
"src/protobuf/protobuf-compiler-main.cc",
]
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
}
......
......@@ -837,6 +837,7 @@ extern macro ChangeFloat32ToFloat64(float32): float64;
extern macro ChangeNumberToFloat64(Number): float64;
extern macro ChangeFloat64ToTagged(float64): Number;
extern macro ChangeFloat64ToUintPtr(float64): uintptr;
extern macro ChangeFloat64ToIntPtr(float64): intptr;
extern macro ChangeInt32ToIntPtr(int32): intptr; // Sign-extends.
extern macro ChangeUint32ToWord(uint32): uintptr; // Doesn't sign-extend.
extern macro LoadNativeContext(Context): NativeContext;
......
......@@ -712,11 +712,8 @@ namespace internal {
CPP(IsPromise) \
/* ES #sec-promise.all */ \
TFJ(PromiseAll, 1, kReceiver, kIterable) \
TFJ(PromiseAllResolveElementClosure, 1, kReceiver, kValue) \
/* ES #sec-promise.allsettled */ \
TFJ(PromiseAllSettled, 1, kReceiver, kIterable) \
TFJ(PromiseAllSettledResolveElementClosure, 1, kReceiver, kValue) \
TFJ(PromiseAllSettledRejectElementClosure, 1, kReceiver, kValue) \
\
/* Reflect */ \
ASM(ReflectApply, JSTrampoline) \
......
......@@ -740,193 +740,5 @@ TF_BUILTIN(PromiseAllSettled, PromiseBuiltinsAssembler) {
});
}
void PromiseBuiltinsAssembler::Generate_PromiseAllResolveElementClosure(
TNode<Context> context, TNode<Object> value, TNode<JSFunction> function,
const CreatePromiseAllResolveElementFunctionValue& callback) {
Label already_called(this, Label::kDeferred), resolve_promise(this);
// We use the {function}s context as the marker to remember whether this
// resolve element closure was already called. It points to the resolve
// element context (which is a FunctionContext) until it was called the
// first time, in which case we make it point to the native context here
// to mark this resolve element closure as done.
GotoIf(IsNativeContext(context), &already_called);
CSA_ASSERT(
this,
SmiEqual(LoadObjectField<Smi>(context, Context::kLengthOffset),
SmiConstant(PromiseBuiltins::kPromiseAllResolveElementLength)));
TNode<NativeContext> native_context = LoadNativeContext(context);
StoreObjectField(function, JSFunction::kContextOffset, native_context);
// Update the value depending on whether Promise.all or
// Promise.allSettled is called.
value = callback(context, native_context, value);
// Determine the index from the {function}.
Label unreachable(this, Label::kDeferred);
STATIC_ASSERT(PropertyArray::kNoHashSentinel == 0);
TNode<IntPtrT> identity_hash =
LoadJSReceiverIdentityHash(function, &unreachable);
CSA_ASSERT(this, IntPtrGreaterThan(identity_hash, IntPtrConstant(0)));
TNode<IntPtrT> index = IntPtrSub(identity_hash, IntPtrConstant(1));
// Check if we need to grow the [[ValuesArray]] to store {value} at {index}.
TNode<JSArray> values_array = CAST(LoadContextElement(
context, PromiseBuiltins::kPromiseAllResolveElementValuesArraySlot));
TNode<FixedArray> elements = CAST(LoadElements(values_array));
TNode<IntPtrT> values_length =
LoadAndUntagObjectField(values_array, JSArray::kLengthOffset);
Label if_inbounds(this), if_outofbounds(this), done(this);
Branch(IntPtrLessThan(index, values_length), &if_inbounds, &if_outofbounds);
BIND(&if_outofbounds);
{
// Check if we need to grow the backing store.
TNode<IntPtrT> new_length = IntPtrAdd(index, IntPtrConstant(1));
TNode<IntPtrT> elements_length =
LoadAndUntagObjectField(elements, FixedArray::kLengthOffset);
Label if_grow(this, Label::kDeferred), if_nogrow(this);
Branch(IntPtrLessThan(index, elements_length), &if_nogrow, &if_grow);
BIND(&if_grow);
{
// We need to grow the backing store to fit the {index} as well.
TNode<IntPtrT> new_elements_length =
IntPtrMin(CalculateNewElementsCapacity(new_length),
IntPtrConstant(PropertyArray::HashField::kMax + 1));
CSA_ASSERT(this, IntPtrLessThan(index, new_elements_length));
CSA_ASSERT(this, IntPtrLessThan(elements_length, new_elements_length));
TNode<FixedArray> new_elements =
CAST(AllocateFixedArray(PACKED_ELEMENTS, new_elements_length,
AllocationFlag::kAllowLargeObjectAllocation));
CopyFixedArrayElements(PACKED_ELEMENTS, elements, PACKED_ELEMENTS,
new_elements, elements_length,
new_elements_length);
StoreFixedArrayElement(new_elements, index, value);
// Update backing store and "length" on {values_array}.
StoreObjectField(values_array, JSArray::kElementsOffset, new_elements);
StoreObjectFieldNoWriteBarrier(values_array, JSArray::kLengthOffset,
SmiTag(new_length));
Goto(&done);
}
BIND(&if_nogrow);
{
// The {index} is within bounds of the {elements} backing store, so
// just store the {value} and update the "length" of the {values_array}.
StoreObjectFieldNoWriteBarrier(values_array, JSArray::kLengthOffset,
SmiTag(new_length));
StoreFixedArrayElement(elements, index, value);
Goto(&done);
}
}
BIND(&if_inbounds);
{
// The {index} is in bounds of the {values_array},
// just store the {value} and continue.
StoreFixedArrayElement(elements, index, value);
Goto(&done);
}
BIND(&done);
TNode<Smi> remaining_elements_count = CAST(LoadContextElement(
context, PromiseBuiltins::kPromiseAllResolveElementRemainingSlot));
remaining_elements_count = SmiSub(remaining_elements_count, SmiConstant(1));
StoreContextElement(context,
PromiseBuiltins::kPromiseAllResolveElementRemainingSlot,
remaining_elements_count);
GotoIf(SmiEqual(remaining_elements_count, SmiConstant(0)), &resolve_promise);
Return(UndefinedConstant());
BIND(&resolve_promise);
TNode<PromiseCapability> capability = CAST(LoadContextElement(
context, PromiseBuiltins::kPromiseAllResolveElementCapabilitySlot));
TNode<Object> resolve =
LoadObjectField(capability, PromiseCapability::kResolveOffset);
CallJS(CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
context, resolve, UndefinedConstant(), values_array);
Return(UndefinedConstant());
BIND(&already_called);
Return(UndefinedConstant());
BIND(&unreachable);
Unreachable();
}
TF_BUILTIN(PromiseAllResolveElementClosure, PromiseBuiltinsAssembler) {
TNode<Object> value = CAST(Parameter(Descriptor::kValue));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<JSFunction> function = CAST(Parameter(Descriptor::kJSTarget));
Generate_PromiseAllResolveElementClosure(
context, value, function,
[](TNode<Object>, TNode<NativeContext>, TNode<Object> value) {
return value;
});
}
TF_BUILTIN(PromiseAllSettledResolveElementClosure, PromiseBuiltinsAssembler) {
TNode<Object> value = CAST(Parameter(Descriptor::kValue));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<JSFunction> function = CAST(Parameter(Descriptor::kJSTarget));
Generate_PromiseAllResolveElementClosure(
context, value, function,
[this](TNode<Context> context, TNode<NativeContext> native_context,
TNode<Object> value) {
// TODO(gsathya): Optimize the creation using a cached map to
// prevent transitions here.
// 9. Let obj be ! ObjectCreate(%ObjectPrototype%).
TNode<HeapObject> object_function = Cast(
LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX));
TNode<Map> object_function_map = Cast(LoadObjectField(
object_function, JSFunction::kPrototypeOrInitialMapOffset));
TNode<JSObject> obj = AllocateJSObjectFromMap(object_function_map);
// 10. Perform ! CreateDataProperty(obj, "status", "fulfilled").
CallBuiltin(Builtins::kFastCreateDataProperty, context, obj,
StringConstant("status"), StringConstant("fulfilled"));
// 11. Perform ! CreateDataProperty(obj, "value", x).
CallBuiltin(Builtins::kFastCreateDataProperty, context, obj,
StringConstant("value"), value);
return obj;
});
}
TF_BUILTIN(PromiseAllSettledRejectElementClosure, PromiseBuiltinsAssembler) {
TNode<Object> value = CAST(Parameter(Descriptor::kValue));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<JSFunction> function = CAST(Parameter(Descriptor::kJSTarget));
Generate_PromiseAllResolveElementClosure(
context, value, function,
[this](TNode<Context> context, TNode<NativeContext> native_context,
TNode<Object> value) {
// TODO(gsathya): Optimize the creation using a cached map to
// prevent transitions here.
// 9. Let obj be ! ObjectCreate(%ObjectPrototype%).
TNode<HeapObject> object_function = Cast(
LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX));
TNode<Map> object_function_map = Cast(LoadObjectField(
object_function, JSFunction::kPrototypeOrInitialMapOffset));
TNode<JSObject> obj = AllocateJSObjectFromMap(object_function_map);
// 10. Perform ! CreateDataProperty(obj, "status", "rejected").
CallBuiltin(Builtins::kFastCreateDataProperty, context, obj,
StringConstant("status"), StringConstant("rejected"));
// 11. Perform ! CreateDataProperty(obj, "reason", x).
CallBuiltin(Builtins::kFastCreateDataProperty, context, obj,
StringConstant("reason"), value);
return obj;
});
}
} // namespace internal
} // namespace v8
......@@ -167,15 +167,6 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler {
TNode<Context> context, TNode<Object> receiver, TNode<Object> iterable,
const PromiseAllResolvingElementFunction& create_resolve_element_function,
const PromiseAllResolvingElementFunction& create_reject_element_function);
using CreatePromiseAllResolveElementFunctionValue =
std::function<TNode<Object>(TNode<Context> context,
TNode<NativeContext> native_context,
TNode<Object> value)>;
void Generate_PromiseAllResolveElementClosure(
TNode<Context> context, TNode<Object> value, TNode<JSFunction> function,
const CreatePromiseAllResolveElementFunctionValue& callback);
};
} // namespace internal
......
......@@ -227,6 +227,9 @@ Convert<float64, uintptr>(ui: uintptr): float64 {
Convert<Number, uintptr>(ui: uintptr): Number {
return ChangeUintPtrToTagged(ui);
}
Convert<Number, intptr>(i: intptr): Number {
return ChangeUintPtrToTagged(Unsigned(i));
}
Convert<uintptr, float64>(d: float64): uintptr {
return ChangeFloat64ToUintPtr(d);
}
......@@ -239,6 +242,9 @@ Convert<uintptr, RawPtr>(r: RawPtr): uintptr {
Convert<intptr, RawPtr>(r: RawPtr): intptr {
return Signed(r);
}
Convert<intptr, Number>(n: Number): intptr {
return ChangeFloat64ToIntPtr(ChangeNumberToFloat64(n));
}
Convert<bint, int32>(v: int32): bint {
return IntPtrToBInt(Convert<intptr>(v));
}
......
// Copyright 2019 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-promise.h'
#include 'src/builtins/builtins-promise-gen.h'
#include 'src/objects/property-array.h'
namespace promise {
struct PromiseAllWrapResultAsFulfilledFunctor {
macro Call(_nativeContext: NativeContext, value: JSAny): JSAny {
return value;
}
}
struct PromiseAllSettledWrapResultAsFulfilledFunctor {
transitioning
macro Call(implicit context: Context)(
nativeContext: NativeContext, value: JSAny): JSAny {
// TODO(gsathya): Optimize the creation using a cached map to
// prevent transitions here.
// 9. Let obj be ! ObjectCreate(%ObjectPrototype%).
const objectFunction = UnsafeCast<JSFunction>(
nativeContext[NativeContextSlot::OBJECT_FUNCTION_INDEX]);
const objectFunctionMap =
UnsafeCast<Map>(objectFunction.prototype_or_initial_map);
const obj = AllocateJSObjectFromMap(objectFunctionMap);
// 10. Perform ! CreateDataProperty(obj, "status", "fulfilled").
FastCreateDataProperty(
obj, StringConstant('status'), StringConstant('fulfilled'));
// 11. Perform ! CreateDataProperty(obj, "value", x).
FastCreateDataProperty(obj, StringConstant('value'), value);
return obj;
}
}
struct PromiseAllSettledWrapResultAsRejectedFunctor {
transitioning
macro Call(implicit context: Context)(
nativeContext: NativeContext, value: JSAny): JSAny {
// TODO(gsathya): Optimize the creation using a cached map to
// prevent transitions here.
// 9. Let obj be ! ObjectCreate(%ObjectPrototype%).
const objectFunction = UnsafeCast<JSFunction>(
nativeContext[NativeContextSlot::OBJECT_FUNCTION_INDEX]);
const objectFunctionMap =
UnsafeCast<Map>(objectFunction.prototype_or_initial_map);
const obj = AllocateJSObjectFromMap(objectFunctionMap);
// 10. Perform ! CreateDataProperty(obj, "status", "rejected").
FastCreateDataProperty(
obj, StringConstant('status'), StringConstant('rejected'));
// 11. Perform ! CreateDataProperty(obj, "reason", x).
FastCreateDataProperty(obj, StringConstant('reason'), value);
return obj;
}
}
extern macro LoadJSReceiverIdentityHash(Object): intptr labels IfNoHash;
extern enum PromiseAllResolveElementContextSlots extends int31
constexpr 'PromiseBuiltins::PromiseAllResolveElementContextSlots' {
kPromiseAllResolveElementRemainingSlot,
kPromiseAllResolveElementCapabilitySlot,
kPromiseAllResolveElementValuesArraySlot,
kPromiseAllResolveElementLength
}
extern operator '[]=' macro StoreContextElement(
Context, constexpr PromiseAllResolveElementContextSlots, Object): void;
extern operator '[]' macro LoadContextElement(
Context, constexpr PromiseAllResolveElementContextSlots): Object;
const kPropertyArrayNoHashSentinel: constexpr int31
generates 'PropertyArray::kNoHashSentinel';
const kPropertyArrayHashFieldMax: constexpr int31
generates 'PropertyArray::HashField::kMax';
transitioning macro PromiseAllResolveElementClosure<F: type>(
implicit context:
Context)(value: JSAny, function: JSFunction, wrapResultFunctor: F):
JSAny {
// We use the {function}s context as the marker to remember whether this
// resolve element closure was already called. It points to the resolve
// element context (which is a FunctionContext) until it was called the
// first time, in which case we make it point to the native context here
// to mark this resolve element closure as done.
if (IsNativeContext(context)) deferred {
return Undefined;
}
assert(
context.length ==
PromiseAllResolveElementContextSlots::kPromiseAllResolveElementLength);
const nativeContext = LoadNativeContext(context);
function.context = nativeContext;
// Update the value depending on whether Promise.all or
// Promise.allSettled is called.
const updatedValue = wrapResultFunctor.Call(nativeContext, value);
// Determine the index from the {function}.
assert(kPropertyArrayNoHashSentinel == 0);
const identityHash =
LoadJSReceiverIdentityHash(function) otherwise unreachable;
assert(identityHash > 0);
const index = identityHash - 1;
// Check if we need to grow the [[ValuesArray]] to store {value} at {index}.
const valuesArray = UnsafeCast<JSArray>(
context[PromiseAllResolveElementContextSlots::
kPromiseAllResolveElementValuesArraySlot]);
const elements = UnsafeCast<FixedArray>(valuesArray.elements);
const valuesLength = Convert<intptr>(valuesArray.length);
if (index < valuesLength) {
// The {index} is in bounds of the {values_array},
// just store the {value} and continue.
elements.objects[index] = updatedValue;
} else {
// Check if we need to grow the backing store.
const newLength = index + 1;
const elementsLength = elements.length_intptr;
if (index < elementsLength) {
// The {index} is within bounds of the {elements} backing store, so
// just store the {value} and update the "length" of the {values_array}.
valuesArray.length = Convert<Smi>(newLength);
elements.objects[index] = updatedValue;
} else
deferred {
// We need to grow the backing store to fit the {index} as well.
const newElementsLength = IntPtrMin(
CalculateNewElementsCapacity(newLength),
kPropertyArrayHashFieldMax + 1);
assert(index < newElementsLength);
assert(elementsLength < newElementsLength);
const newElements =
ExtractFixedArray(elements, 0, elementsLength, newElementsLength);
newElements.objects[index] = updatedValue;
// Update backing store and "length" on {values_array}.
valuesArray.elements = newElements;
valuesArray.length = Convert<Smi>(newLength);
}
}
let remainingElementsCount =
UnsafeCast<Smi>(context[PromiseAllResolveElementContextSlots::
kPromiseAllResolveElementRemainingSlot]);
remainingElementsCount = remainingElementsCount - 1;
context[PromiseAllResolveElementContextSlots::
kPromiseAllResolveElementRemainingSlot] =
remainingElementsCount;
if (remainingElementsCount == 0) {
const capability = UnsafeCast<PromiseCapability>(
context[PromiseAllResolveElementContextSlots::
kPromiseAllResolveElementCapabilitySlot]);
const resolve = UnsafeCast<JSAny>(capability.resolve);
Call(context, resolve, Undefined, valuesArray);
}
return Undefined;
}
transitioning javascript builtin
PromiseAllResolveElementClosure(
js-implicit context: Context, receiver: JSAny,
target: JSFunction)(value: JSAny): JSAny {
return PromiseAllResolveElementClosure(
value, target, PromiseAllWrapResultAsFulfilledFunctor{});
}
transitioning javascript builtin
PromiseAllSettledResolveElementClosure(
js-implicit context: Context, receiver: JSAny,
target: JSFunction)(value: JSAny): JSAny {
return PromiseAllResolveElementClosure(
value, target, PromiseAllSettledWrapResultAsFulfilledFunctor{});
}
transitioning javascript builtin
PromiseAllSettledRejectElementClosure(
js-implicit context: Context, receiver: JSAny,
target: JSFunction)(value: JSAny): JSAny {
return PromiseAllResolveElementClosure(
value, target, PromiseAllSettledWrapResultAsRejectedFunctor{});
}
}
......@@ -4978,8 +4978,10 @@ TNode<FixedArrayBase> CodeStubAssembler::GrowElementsCapacity(
// Copy the elements from the old elements store to the new.
// The size-check above guarantees that the |new_elements| is allocated
// in new space so we can skip the write barrier.
CopyFixedArrayElements(from_kind, elements, to_kind, new_elements, capacity,
new_capacity, SKIP_WRITE_BARRIER, mode);
CopyFixedArrayElements(from_kind, CAST(elements), to_kind, new_elements,
UncheckedCast<IntPtrT>(capacity),
UncheckedCast<IntPtrT>(new_capacity),
SKIP_WRITE_BARRIER, mode);
StoreObjectField(CAST(object), JSObject::kElementsOffset, new_elements);
Comment("] GrowElementsCapacity");
......
......@@ -2064,8 +2064,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// zero to |to_array| of |capacity| size respecting both array's elements
// kinds.
void CopyFixedArrayElements(
ElementsKind from_kind, Node* from_array, ElementsKind to_kind,
Node* to_array, Node* element_count, Node* capacity,
ElementsKind from_kind, TNode<Object> from_array, ElementsKind to_kind,
TNode<Object> to_array, TNode<IntPtrT> element_count,
TNode<IntPtrT> capacity,
WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
ParameterMode mode = INTPTR_PARAMETERS) {
CopyFixedArrayElements(from_kind, from_array, to_kind, to_array,
......
......@@ -94,10 +94,10 @@ extern macro AllocateFixedDoubleArrayWithHoles(
intptr, constexpr AllocationFlag): FixedDoubleArray;
extern macro CopyFixedArrayElements(
constexpr ElementsKind, FixedArray, constexpr ElementsKind, FixedArray,
intptr, intptr, intptr): void;
intptr, intptr): void;
extern macro CopyFixedArrayElements(
constexpr ElementsKind, FixedArray, constexpr ElementsKind, FixedArray, Smi,
Smi, Smi): void;
constexpr ElementsKind, FixedArray, constexpr ElementsKind, FixedArray,
intptr, intptr, intptr): void;
macro ExtractFixedArray(
source: FixedArray, first: intptr, count: intptr,
......
......@@ -74,6 +74,7 @@ void ImplementationVisitor::BeginCSAFiles() {
UnderlinifyPath(SourceFileMap::PathFromV8Root(file)) + "_H_";
header << "#ifndef " << headerDefine << "\n";
header << "#define " << headerDefine << "\n\n";
header << "#include \"src/builtins/builtins-promise.h\"\n";
header << "#include \"src/compiler/code-assembler.h\"\n";
header << "#include \"src/codegen/code-stub-assembler.h\"\n";
header << "#include \"src/utils/utils.h\"\n";
......
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