1ec867c8a1
* chore: [30-x-y] cherry-pick 11 changes from 3-M126 * d54105311590 from chromium * 43b8b682d05c from chromium * c5dd8839bfaf from chromium * cdbc1d9684a3 from v8 * 38e4483e47f9 from chromium * 70d2fe6b7c47 from v8 * 901377bb2f3b from v8 * 1b9040817119 from chromium * bb28367eed73 from v8 * 99cafbf4b4b9 from chromium * bc545b15a0ee from v8 * chore: update patches * 5639725: [wasm] Fix scanning of wasm-to-js params | https://chromium-review.googlesource.com/c/v8/v8/+/5639725 * 5672472: [M120-LTS] Prevent script injection on reload when racing with a navigation | https://chromium-review.googlesource.com/c/chromium/src/+/5672472
221 lines
10 KiB
Diff
221 lines
10 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Thibaud Michaud <thibaudm@chromium.org>
|
|
Date: Fri, 21 Jun 2024 16:31:15 +0200
|
|
Subject: Fix scanning of wasm-to-js params
|
|
|
|
Wasm-to-js wrappers are sometimes compiled as on-heap Code objects, for
|
|
example when tiering-up from a WasmFuncRef call origin. The frames of
|
|
these functions are mapped to a subclass of TypedFrame, however
|
|
TypedFrame::Iterate() only supports iterating the generic wasm-to-js
|
|
wrapper.
|
|
|
|
Add support for iterating the tagged parameters of optimized wasm-to-js
|
|
wrappers in TypedFrame::Iterate. For this we also add two 16-bit fields
|
|
in the Code object to encode the incoming tagged parameter region, which
|
|
we would normally find in the WasmCode data.
|
|
|
|
R=jkummerow@chromium.org
|
|
|
|
Fixed: 346597059
|
|
Change-Id: I425619fca86c38f91f1ca9cbeb70e7b5a7b2d6c1
|
|
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5639725
|
|
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
|
|
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
|
|
Cr-Commit-Position: refs/heads/main@{#94589}
|
|
|
|
diff --git a/src/compiler/pipeline.cc b/src/compiler/pipeline.cc
|
|
index 0181588337df73bfa97220d895733c40b92bd40b..033469e626ffb35846ae5114632f3dc000400935 100644
|
|
--- a/src/compiler/pipeline.cc
|
|
+++ b/src/compiler/pipeline.cc
|
|
@@ -2295,6 +2295,14 @@ CompilationJob::Status FinalizeWrapperCompilation(
|
|
Handle<AbstractCode>::cast(code),
|
|
info->GetDebugName().get()));
|
|
}
|
|
+ // Set the wasm-to-js specific code fields needed to scan the incoming stack
|
|
+ // parameters.
|
|
+ if (code->kind() == CodeKind::WASM_TO_JS_FUNCTION) {
|
|
+ code->set_wasm_js_tagged_parameter_count(
|
|
+ call_descriptor->GetTaggedParameterSlots() & 0xffff);
|
|
+ code->set_wasm_js_first_tagged_parameter(
|
|
+ call_descriptor->GetTaggedParameterSlots() >> 16);
|
|
+ }
|
|
return CompilationJob::SUCCEEDED;
|
|
}
|
|
return CompilationJob::FAILED;
|
|
diff --git a/src/diagnostics/objects-printer.cc b/src/diagnostics/objects-printer.cc
|
|
index 7677022ce31c1b8ead0cc2eb37fb505b750639be..12bd5b8fd27f67c73938550acc4af1857eace59a 100644
|
|
--- a/src/diagnostics/objects-printer.cc
|
|
+++ b/src/diagnostics/objects-printer.cc
|
|
@@ -2102,7 +2102,14 @@ void Code::CodePrint(std::ostream& os, const char* name, Address current_pc) {
|
|
os << "\n - instruction_size: " << instruction_size();
|
|
os << "\n - metadata_size: " << metadata_size();
|
|
|
|
- os << "\n - inlined_bytecode_size: " << inlined_bytecode_size();
|
|
+ if (kind() != CodeKind::WASM_TO_JS_FUNCTION) {
|
|
+ os << "\n - inlined_bytecode_size: " << inlined_bytecode_size();
|
|
+ } else {
|
|
+ os << "\n - wasm_js_tagged_parameter_count: "
|
|
+ << wasm_js_tagged_parameter_count();
|
|
+ os << "\n - wasm_js_first_tagged_parameter: "
|
|
+ << wasm_js_first_tagged_parameter();
|
|
+ }
|
|
os << "\n - osr_offset: " << osr_offset();
|
|
os << "\n - handler_table_offset: " << handler_table_offset();
|
|
os << "\n - unwinding_info_offset: " << unwinding_info_offset();
|
|
diff --git a/src/execution/frames.cc b/src/execution/frames.cc
|
|
index 92dff2f7e8c8f72e38eef4feb5b10ace9fe2535c..2693fb2a859dc7489ef802c3064beace88608415 100644
|
|
--- a/src/execution/frames.cc
|
|
+++ b/src/execution/frames.cc
|
|
@@ -1562,7 +1562,7 @@ void WasmFrame::Iterate(RootVisitor* v) const {
|
|
frame_header_limit);
|
|
}
|
|
|
|
-void TypedFrame::IterateParamsOfWasmToJSWrapper(RootVisitor* v) const {
|
|
+void TypedFrame::IterateParamsOfGenericWasmToJSWrapper(RootVisitor* v) const {
|
|
Tagged<Object> maybe_signature = Tagged<Object>(
|
|
Memory<Address>(fp() + WasmToJSWrapperConstants::kSignatureOffset));
|
|
if (IsSmi(maybe_signature)) {
|
|
@@ -1678,6 +1678,18 @@ void TypedFrame::IterateParamsOfWasmToJSWrapper(RootVisitor* v) const {
|
|
}
|
|
}
|
|
}
|
|
+
|
|
+void TypedFrame::IterateParamsOfOptimizedWasmToJSWrapper(RootVisitor* v) const {
|
|
+ Tagged<GcSafeCode> code = GcSafeLookupCode();
|
|
+ if (code->wasm_js_tagged_parameter_count() > 0) {
|
|
+ FullObjectSlot tagged_parameter_base(&Memory<Address>(caller_sp()));
|
|
+ tagged_parameter_base += code->wasm_js_first_tagged_parameter();
|
|
+ FullObjectSlot tagged_parameter_limit =
|
|
+ tagged_parameter_base + code->wasm_js_tagged_parameter_count();
|
|
+ v->VisitRootPointers(Root::kStackRoots, nullptr, tagged_parameter_base,
|
|
+ tagged_parameter_limit);
|
|
+ }
|
|
+}
|
|
#endif // V8_ENABLE_WEBASSEMBLY
|
|
|
|
void TypedFrame::Iterate(RootVisitor* v) const {
|
|
@@ -1709,10 +1721,13 @@ void TypedFrame::Iterate(RootVisitor* v) const {
|
|
CHECK(entry->code.has_value());
|
|
Tagged<GcSafeCode> code = entry->code.value();
|
|
#if V8_ENABLE_WEBASSEMBLY
|
|
- bool is_wasm_to_js =
|
|
+ bool is_generic_wasm_to_js =
|
|
code->is_builtin() && code->builtin_id() == Builtin::kWasmToJsWrapperCSA;
|
|
- if (is_wasm_to_js) {
|
|
- IterateParamsOfWasmToJSWrapper(v);
|
|
+ bool is_optimized_wasm_to_js = this->type() == WASM_TO_JS_FUNCTION;
|
|
+ if (is_generic_wasm_to_js) {
|
|
+ IterateParamsOfGenericWasmToJSWrapper(v);
|
|
+ } else if (is_optimized_wasm_to_js) {
|
|
+ IterateParamsOfOptimizedWasmToJSWrapper(v);
|
|
}
|
|
#endif // V8_ENABLE_WEBASSEMBLY
|
|
DCHECK(code->is_turbofanned());
|
|
@@ -1745,10 +1760,14 @@ void TypedFrame::Iterate(RootVisitor* v) const {
|
|
// wrapper switched to before pushing the outgoing stack parameters and
|
|
// calling the target. It marks the limit of the stack param area, and is
|
|
// distinct from the beginning of the spill area.
|
|
- Address central_stack_sp =
|
|
- Memory<Address>(fp() + WasmToJSWrapperConstants::kCentralStackSPOffset);
|
|
+ int central_stack_sp_offset =
|
|
+ is_generic_wasm_to_js
|
|
+ ? WasmToJSWrapperConstants::kCentralStackSPOffset
|
|
+ : WasmImportWrapperFrameConstants::kCentralStackSPOffset;
|
|
+ Address central_stack_sp = Memory<Address>(fp() + central_stack_sp_offset);
|
|
FullObjectSlot parameters_limit(
|
|
- is_wasm_to_js && central_stack_sp != kNullAddress
|
|
+ (is_generic_wasm_to_js || is_optimized_wasm_to_js) &&
|
|
+ central_stack_sp != kNullAddress
|
|
? central_stack_sp
|
|
: frame_header_base.address() - spill_slots_size);
|
|
#else
|
|
diff --git a/src/execution/frames.h b/src/execution/frames.h
|
|
index 081c74bf124ccfa57e4b40f75cbe42b00c771b2e..908239b4161235aeda04fe5526ddea8d56b09425 100644
|
|
--- a/src/execution/frames.h
|
|
+++ b/src/execution/frames.h
|
|
@@ -634,7 +634,8 @@ class TypedFrame : public CommonFrame {
|
|
Tagged<HeapObject> unchecked_code() const override { return {}; }
|
|
void Iterate(RootVisitor* v) const override;
|
|
|
|
- void IterateParamsOfWasmToJSWrapper(RootVisitor* v) const;
|
|
+ void IterateParamsOfGenericWasmToJSWrapper(RootVisitor* v) const;
|
|
+ void IterateParamsOfOptimizedWasmToJSWrapper(RootVisitor* v) const;
|
|
|
|
protected:
|
|
inline explicit TypedFrame(StackFrameIteratorBase* iterator);
|
|
diff --git a/src/objects/code-inl.h b/src/objects/code-inl.h
|
|
index baaced29afdbc87eae1c34b8df779e17e41410c4..1e1d66a87ee633cbdb49265444f53b5db790d9dd 100644
|
|
--- a/src/objects/code-inl.h
|
|
+++ b/src/objects/code-inl.h
|
|
@@ -48,6 +48,8 @@ GCSAFE_CODE_FWD_ACCESSOR(bool, has_tagged_outgoing_params)
|
|
GCSAFE_CODE_FWD_ACCESSOR(bool, marked_for_deoptimization)
|
|
GCSAFE_CODE_FWD_ACCESSOR(Tagged<Object>, raw_instruction_stream)
|
|
GCSAFE_CODE_FWD_ACCESSOR(int, stack_slots)
|
|
+GCSAFE_CODE_FWD_ACCESSOR(uint16_t, wasm_js_tagged_parameter_count)
|
|
+GCSAFE_CODE_FWD_ACCESSOR(uint16_t, wasm_js_first_tagged_parameter)
|
|
GCSAFE_CODE_FWD_ACCESSOR(Address, constant_pool)
|
|
GCSAFE_CODE_FWD_ACCESSOR(Address, safepoint_table_address)
|
|
#undef GCSAFE_CODE_FWD_ACCESSOR
|
|
@@ -428,6 +430,31 @@ void Code::set_inlined_bytecode_size(unsigned size) {
|
|
RELAXED_WRITE_UINT_FIELD(*this, kInlinedBytecodeSizeOffset, size);
|
|
}
|
|
|
|
+// For optimized on-heap wasm-js wrappers, we repurpose the (otherwise unused)
|
|
+// 32-bit InlinedBytecodeSize field to encode two 16 values needed for scanning
|
|
+// the frame: the count and starting offset of incoming tagged parameters.
|
|
+// TODO(wasm): Eventually the wrappers should be managed off-heap by the wasm
|
|
+// engine. Remove these accessors when that is the case.
|
|
+void Code::set_wasm_js_tagged_parameter_count(uint16_t count) {
|
|
+ DCHECK_EQ(kind(), CodeKind::WASM_TO_JS_FUNCTION);
|
|
+ RELAXED_WRITE_UINT16_FIELD(*this, kInlinedBytecodeSizeOffset, count);
|
|
+}
|
|
+
|
|
+uint16_t Code::wasm_js_tagged_parameter_count() const {
|
|
+ DCHECK_EQ(kind(), CodeKind::WASM_TO_JS_FUNCTION);
|
|
+ return RELAXED_READ_UINT16_FIELD(*this, kInlinedBytecodeSizeOffset);
|
|
+}
|
|
+
|
|
+void Code::set_wasm_js_first_tagged_parameter(uint16_t count) {
|
|
+ DCHECK_EQ(kind(), CodeKind::WASM_TO_JS_FUNCTION);
|
|
+ RELAXED_WRITE_UINT16_FIELD(*this, kInlinedBytecodeSizeOffset + 2, count);
|
|
+}
|
|
+
|
|
+uint16_t Code::wasm_js_first_tagged_parameter() const {
|
|
+ DCHECK_EQ(kind(), CodeKind::WASM_TO_JS_FUNCTION);
|
|
+ return RELAXED_READ_UINT16_FIELD(*this, kInlinedBytecodeSizeOffset + 2);
|
|
+}
|
|
+
|
|
BytecodeOffset Code::osr_offset() const {
|
|
return BytecodeOffset(RELAXED_READ_INT32_FIELD(*this, kOsrOffsetOffset));
|
|
}
|
|
diff --git a/src/objects/code.h b/src/objects/code.h
|
|
index 9a079a94ba0126b24532362a0ce233477f42c221..1da011899807125d6dc9ffb6d56622f5f15ad465 100644
|
|
--- a/src/objects/code.h
|
|
+++ b/src/objects/code.h
|
|
@@ -124,6 +124,15 @@ class Code : public ExposedTrustedObject {
|
|
// [deoptimization_data]: Array containing data for deopt for non-baseline
|
|
// code.
|
|
DECL_ACCESSORS(deoptimization_data, Tagged<TrustedFixedArray>)
|
|
+ // [parameter_count]: The number of formal parameters, including the
|
|
+ // receiver. Currently only available for optimized functions.
|
|
+ // TODO(saelo): make this always available. This is just a matter of figuring
|
|
+ // out how to obtain the parameter count during code generation when no
|
|
+ // BytecodeArray is available from which it can be copied.
|
|
+ DECL_PRIMITIVE_ACCESSORS(parameter_count, uint16_t)
|
|
+ inline uint16_t parameter_count_without_receiver() const;
|
|
+ DECL_PRIMITIVE_ACCESSORS(wasm_js_tagged_parameter_count, uint16_t)
|
|
+ DECL_PRIMITIVE_ACCESSORS(wasm_js_first_tagged_parameter, uint16_t)
|
|
|
|
// Whether this type of Code uses deoptimization data, in which case the
|
|
// deoptimization_data field will be populated.
|
|
@@ -503,6 +512,10 @@ class GcSafeCode : public HeapObject {
|
|
inline bool CanDeoptAt(Isolate* isolate, Address pc) const;
|
|
inline Tagged<Object> raw_instruction_stream(
|
|
PtrComprCageBase code_cage_base) const;
|
|
+ // The two following accessors repurpose the InlinedBytecodeSize field, see
|
|
+ // comment in code-inl.h.
|
|
+ inline uint16_t wasm_js_tagged_parameter_count() const;
|
|
+ inline uint16_t wasm_js_first_tagged_parameter() const;
|
|
|
|
private:
|
|
OBJECT_CONSTRUCTORS(GcSafeCode, HeapObject);
|