Skip to content

Commit 0f98039

Browse files
deps: patch V8 to support compilation with MSVC
Co-Authored-By: Michaël Zasso <targos@protonmail.com> PR-URL: #58070 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
1 parent ffadf35 commit 0f98039

21 files changed

+147
-60
lines changed

common.gypi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
# Reset this number to 0 on major V8 upgrades.
4040
# Increment by one for each non-official patch applied to deps/v8.
41-
'v8_embedder_string': '-node.8',
41+
'v8_embedder_string': '-node.9',
4242

4343
##### V8 defaults for Node.js #####
4444

deps/v8/src/base/fpu.cc

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,21 @@ void FPU::SetFlushDenormals(bool value) {
5757
#elif defined(V8_HOST_ARCH_ARM64) || defined(V8_HOST_ARCH_ARM)
5858

5959
namespace {
60+
#if defined(V8_HOST_ARCH_ARM64) && defined(_MSC_VER) && !defined(__clang__)
61+
#include <intrin.h>
62+
#endif
63+
6064
// Bit 24 is the flush-to-zero mode control bit. Setting it to 1 flushes
6165
// denormals to 0.
6266
constexpr int kFlushDenormToZeroBit = (1 << 24);
6367
int GetStatusWord() {
6468
int result;
6569
#if defined(V8_HOST_ARCH_ARM64)
66-
asm volatile("mrs %x[result], FPCR" : [result] "=r"(result));
70+
# if defined(_MSC_VER) && !defined(__clang__)
71+
result = _ReadStatusReg(ARM64_FPCR);
72+
# else
73+
asm volatile("mrs %x[result], FPCR" : [result] "=r"(result));
74+
# endif
6775
#else
6876
asm volatile("vmrs %[result], FPSCR" : [result] "=r"(result));
6977
#endif
@@ -72,7 +80,11 @@ int GetStatusWord() {
7280

7381
void SetStatusWord(int a) {
7482
#if defined(V8_HOST_ARCH_ARM64)
75-
asm volatile("msr FPCR, %x[src]" : : [src] "r"(a));
83+
# if defined(_MSC_VER) && !defined(__clang__)
84+
_WriteStatusReg(ARM64_FPCR, a);
85+
# else
86+
asm volatile("msr FPCR, %x[src]" : : [src] "r"(a));
87+
# endif
7688
#else
7789
asm volatile("vmsr FPSCR, %[src]" : : [src] "r"(a));
7890
#endif

deps/v8/src/codegen/arm64/assembler-arm64.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,10 @@ class AssemblerZone {
168168
public:
169169
explicit AssemblerZone(const MaybeAssemblerZone& zone)
170170
// Create a fresh Zone unless one is already provided.
171-
: maybe_local_zone_(
172-
std::holds_alternative<Zone*>(zone)
173-
? std::nullopt
174-
: std::make_optional<Zone>(std::get<AccountingAllocator*>(zone),
175-
ZONE_NAME)),
171+
: maybe_local_zone_(),
176172
zone_(std::holds_alternative<Zone*>(zone)
177173
? std::get<Zone*>(zone)
178-
: &maybe_local_zone_.value()) {}
174+
: &maybe_local_zone_.emplace(std::get<AccountingAllocator*>(zone), ZONE_NAME)) {}
179175

180176
Zone* get() const { return zone_; }
181177

deps/v8/src/compiler/js-heap-broker.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@ ElementAccessFeedback const& JSHeapBroker::ProcessFeedbackMapsForElementAccess(
879879
Tagged<Map> transition_target;
880880

881881
// Don't generate elements kind transitions from stable maps.
882-
if (!map.is_stable()) {
882+
if (!map.is_stable() && possible_transition_targets.begin() != possible_transition_targets.end()) {
883883
// The lock is needed for UnusedPropertyFields (called deep inside
884884
// FindElementsKindTransitionedMap).
885885
MapUpdaterGuardIfNeeded mumd_scope(this);

deps/v8/src/execution/frames.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,11 +1292,11 @@ class WasmFrame : public TypedFrame {
12921292
FrameSummaries Summarize() const override;
12931293

12941294
static WasmFrame* cast(StackFrame* frame) {
1295-
DCHECK(frame->is_wasm()
12961295
#ifdef V8_ENABLE_DRUMBRAKE
1297-
&& !frame->is_wasm_interpreter_entry()
1296+
DCHECK(frame->is_wasm() && !frame->is_wasm_interpreter_entry());
1297+
#else
1298+
DCHECK(frame->is_wasm());
12981299
#endif // V8_ENABLE_DRUMBRAKE
1299-
);
13001300
return static_cast<WasmFrame*>(frame);
13011301
}
13021302

deps/v8/src/execution/isolate.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,10 +574,14 @@ using DebugObjectCache = std::vector<Handle<HeapObject>>;
574574
#define THREAD_LOCAL_TOP_ADDRESS(type, name) \
575575
inline type* name##_address() { return &thread_local_top()->name##_; }
576576

577+
#if defined(_MSC_VER)
578+
extern thread_local Isolate* g_current_isolate_ V8_CONSTINIT;
579+
#else
577580
// Do not use this variable directly, use Isolate::Current() instead.
578581
// Defined outside of Isolate because Isolate uses V8_EXPORT_PRIVATE.
579582
__attribute__((tls_model(V8_TLS_MODEL))) extern thread_local Isolate*
580583
g_current_isolate_ V8_CONSTINIT;
584+
#endif // defined(_MSC_VER)
581585

582586
// HiddenFactory exists so Isolate can privately inherit from it without making
583587
// Factory's members available to Isolate directly.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
; Copyright 2020 the V8 project authors. All rights reserved.
2+
; Use of this source code is governed by a BSD-style license that can be
3+
; found in the LICENSE file.
4+
5+
; This file is exactly the same as push_registers_asm.cc, just formatted for
6+
; the Microsoft Arm Assembler.
7+
8+
AREA |.text|, CODE, ALIGN=4, READONLY
9+
EXPORT PushAllRegistersAndIterateStack
10+
PushAllRegistersAndIterateStack
11+
; x19-x29 are callee-saved
12+
STP x19, x20, [sp, #-16]!
13+
STP x21, x22, [sp, #-16]!
14+
STP x23, x24, [sp, #-16]!
15+
STP x25, x26, [sp, #-16]!
16+
STP x27, x28, [sp, #-16]!
17+
STP fp, lr, [sp, #-16]!
18+
; Maintain frame pointer
19+
MOV fp, sp
20+
; Pass 1st parameter (x0) unchanged (Stack*).
21+
; Pass 2nd parameter (x1) unchanged (StackVisitor*).
22+
; Save 3rd parameter (x2; IterateStackCallback)
23+
MOV x7, x2
24+
; Pass 3rd parameter as sp (stack pointer)
25+
MOV x2, sp
26+
BLR x7
27+
; Load return address
28+
LDR lr, [sp, #8]
29+
; Restore frame pointer and pop all callee-saved registers.
30+
LDR fp, [sp], #96
31+
RET
32+
END

deps/v8/src/heap/local-heap.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,14 @@ class MarkingBarrier;
3333
class MutablePageMetadata;
3434
class Safepoint;
3535

36+
#if defined(_MSC_VER)
37+
extern thread_local LocalHeap* g_current_local_heap_ V8_CONSTINIT;
38+
#else
3639
// Do not use this variable directly, use LocalHeap::Current() instead.
3740
// Defined outside of LocalHeap because LocalHeap uses V8_EXPORT_PRIVATE.
3841
__attribute__((tls_model(V8_TLS_MODEL))) extern thread_local LocalHeap*
3942
g_current_local_heap_ V8_CONSTINIT;
43+
#endif // defined(_MSC_VER)
4044

4145
// LocalHeap is used by the GC to track all threads with heap access in order to
4246
// stop them before performing a collection. LocalHeaps can be either Parked or

deps/v8/src/maglev/maglev-graph-builder.cc

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11003,13 +11003,19 @@ MaybeReduceResult MaglevGraphBuilder::TryReduceCallForNewClosure(
1100311003
return BuildCallRuntime(Runtime::kThrowConstructorNonCallableError,
1100411004
{target_node});
1100511005
}
11006-
RETURN_IF_DONE(TryBuildCallKnownJSFunction(
11006+
11007+
#ifdef V8_ENABLE_LEAPTIERING
11008+
RETURN_IF_DONE(TryBuildCallKnownJSFunction(
1100711009
target_context, target_node,
1100811010
GetRootConstant(RootIndex::kUndefinedValue),
11009-
#ifdef V8_ENABLE_LEAPTIERING
1101011011
dispatch_handle,
11011-
#endif
1101211012
shared, feedback_cell, args, feedback_source));
11013+
#else
11014+
RETURN_IF_DONE(TryBuildCallKnownJSFunction(
11015+
target_context, target_node,
11016+
GetRootConstant(RootIndex::kUndefinedValue),
11017+
shared, feedback_cell, args, feedback_source));
11018+
#endif
1101311019
}
1101411020
return BuildGenericCall(target_node, Call::TargetType::kJSFunction, args);
1101511021
}

deps/v8/src/objects/instance-type-inl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ HEAP_OBJECT_TYPE_LIST(DECL_TYPE)
4242
// Instance types which are associated with one unique map.
4343

4444
template <class type>
45-
V8_INLINE consteval std::optional<RootIndex> UniqueMapOfInstanceTypeCheck() {
45+
V8_INLINE constexpr std::optional<RootIndex> UniqueMapOfInstanceTypeCheck() {
4646
return {};
4747
}
4848

4949
#define INSTANCE_TYPE_MAP(V, rootIndexName, rootAccessorName, class_name) \
5050
template <> \
51-
V8_INLINE consteval std::optional<RootIndex> \
51+
V8_INLINE constexpr std::optional<RootIndex> \
5252
UniqueMapOfInstanceTypeCheck<InstanceTypeTraits::class_name>() { \
5353
return {RootIndex::k##rootIndexName}; \
5454
}

deps/v8/src/objects/tagged-field.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,10 @@ static_assert(sizeof(UnalignedDoubleMember) == sizeof(double));
121121
#define FLEXIBLE_ARRAY_MEMBER(Type, name) \
122122
using FlexibleDataReturnType = Type[0]; \
123123
FlexibleDataReturnType& name() { \
124-
static_assert(alignof(Type) <= alignof(decltype(*this))); \
125124
using ReturnType = Type[0]; \
126125
return reinterpret_cast<ReturnType&>(*(this + 1)); \
127126
} \
128127
const FlexibleDataReturnType& name() const { \
129-
static_assert(alignof(Type) <= alignof(decltype(*this))); \
130128
using ReturnType = Type[0]; \
131129
return reinterpret_cast<const ReturnType&>(*(this + 1)); \
132130
} \

deps/v8/src/runtime/runtime-test.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,8 +1204,8 @@ RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) {
12041204
namespace {
12051205

12061206
int FixedArrayLenFromSize(int size) {
1207-
return std::min({(size - OFFSET_OF_DATA_START(FixedArray)) / kTaggedSize,
1208-
FixedArray::kMaxRegularLength});
1207+
return std::min<int>((size - OFFSET_OF_DATA_START(FixedArray)) / kTaggedSize,
1208+
static_cast<int>(FixedArray::kMaxRegularLength));
12091209
}
12101210

12111211
void FillUpOneNewSpacePage(Isolate* isolate, Heap* heap,

deps/v8/src/wasm/wasm-objects.cc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3009,15 +3009,21 @@ DirectHandle<WasmExportedFunction> WasmExportedFunction::New(
30093009
DirectHandle<WasmFuncRef> func_ref,
30103010
DirectHandle<WasmInternalFunction> internal_function, int arity,
30113011
DirectHandle<Code> export_wrapper) {
3012+
#if V8_ENABLE_DRUMBRAKE
30123013
DCHECK(CodeKind::JS_TO_WASM_FUNCTION == export_wrapper->kind() ||
30133014
(export_wrapper->is_builtin() &&
30143015
(export_wrapper->builtin_id() == Builtin::kJSToWasmWrapper ||
3015-
#if V8_ENABLE_DRUMBRAKE
30163016
export_wrapper->builtin_id() ==
30173017
Builtin::kGenericJSToWasmInterpreterWrapper ||
3018-
#endif // V8_ENABLE_DRUMBRAKE
30193018
export_wrapper->builtin_id() == Builtin::kWasmPromising ||
30203019
export_wrapper->builtin_id() == Builtin::kWasmStressSwitch)));
3020+
#else
3021+
DCHECK(CodeKind::JS_TO_WASM_FUNCTION == export_wrapper->kind() ||
3022+
(export_wrapper->is_builtin() &&
3023+
(export_wrapper->builtin_id() == Builtin::kJSToWasmWrapper ||
3024+
export_wrapper->builtin_id() == Builtin::kWasmPromising ||
3025+
export_wrapper->builtin_id() == Builtin::kWasmStressSwitch)));
3026+
#endif // V8_ENABLE_DRUMBRAKE
30213027
int func_index = internal_function->function_index();
30223028
Factory* factory = isolate->factory();
30233029
DirectHandle<Map> rtt;

deps/v8/third_party/rapidhash-v8/rapidhash.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,13 @@ struct PlainHashReader {
153153
/*
154154
* Likely and unlikely macros.
155155
*/
156-
#define _likely_(x) __builtin_expect(x, 1)
157-
#define _unlikely_(x) __builtin_expect(x, 0)
156+
#if defined(_MSC_VER) && !defined(__clang__)
157+
#define _likely_(x) (x)
158+
#define _unlikely_(x) (x)
159+
#else
160+
#define _likely_(x) __builtin_expect(x, 1)
161+
#define _unlikely_(x) __builtin_expect(x, 0)
162+
#endif
158163

159164
/*
160165
* Default seed.

test/addons/esm-export/binding.gyp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
'targets': [
3+
{
4+
'target_name': 'binding-export-default',
5+
'sources': [ 'binding-export-default.cc' ],
6+
'includes': ['../common.gypi'],
7+
},
8+
{
9+
'target_name': 'binding-export-primitive',
10+
'sources': [ 'binding-export-primitive.cc' ],
11+
'includes': ['../common.gypi'],
12+
},
13+
]
14+
}

test/addons/esm-export/test-esm.mjs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* This file is supposed to be loaded by `test-import.js` and `test-require.js`
3+
* to verify that `import('*.node')` is working properly either been loaded with
4+
* the ESM loader or the CJS loader.
5+
*/
6+
7+
import { buildType } from '../../common/index.mjs';
8+
import assert from 'node:assert';
9+
import { createRequire } from 'node:module';
10+
import { pathToFileURL } from 'node:url';
11+
12+
const require = createRequire(import.meta.url);
13+
14+
export async function run() {
15+
// binding-export-default.node
16+
{
17+
const bindingPath = require.resolve(`./build/${buildType}/binding-export-default.node`);
18+
// Test with order of require+import
19+
const bindingRequire = require(bindingPath);
20+
const ns = await import(pathToFileURL(bindingPath));
21+
assert.strictEqual(ns.default, bindingRequire);
22+
23+
// As same as ESM-import-CJS, the default export is the value of `module.exports`.
24+
assert.strictEqual(ns.default, ns['module.exports']);
25+
assert.strictEqual(ns.default.default(), 'hello world');
26+
}
27+
28+
// binding-export-primitive.node
29+
{
30+
const bindingPath = require.resolve(`./build/${buildType}/binding-export-primitive.node`);
31+
const ns = await import(pathToFileURL(bindingPath));
32+
33+
// As same as ESM-import-CJS, the default export is the value of `module.exports`.
34+
assert.strictEqual(ns.default, ns['module.exports']);
35+
assert.strictEqual(ns.default, 'hello world');
36+
}
37+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Flags: --experimental-addon-modules
2+
'use strict';
3+
const common = require('../../common');
4+
5+
require('./test-esm.mjs')
6+
.run().then(common.mustCall());

test/addons/esm/binding.gyp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,13 @@
11
{
22
'variables': {
3-
'source_dir': '<!(<(python) -c "import os; print(os.getcwd())")',
3+
'source_dir': '<!("<(python)" -c "import os; print(os.getcwd())")',
44
},
55
'targets': [
66
{
77
'target_name': 'binding',
88
'sources': [ 'binding.cc' ],
99
'includes': ['../common.gypi'],
1010
},
11-
{
12-
'target_name': 'binding-export-default',
13-
'sources': [ 'binding-export-default.cc' ],
14-
'includes': ['../common.gypi'],
15-
},
16-
{
17-
'target_name': 'binding-export-primitive',
18-
'sources': [ 'binding-export-primitive.cc' ],
19-
'includes': ['../common.gypi'],
20-
},
2111
{
2212
'target_name': 'node_modules',
2313
'type': 'none',

test/addons/esm/test-esm.mjs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,4 @@ export async function run() {
3131
assert.strictEqual(rebinding.hello(), 'world');
3232
assert.strictEqual(binding.hello, rebinding.hello);
3333
}
34-
35-
// binding-export-default.node
36-
{
37-
const bindingPath = require.resolve(`./build/${buildType}/binding-export-default.node`);
38-
// Test with order of require+import
39-
const bindingRequire = require(bindingPath);
40-
const ns = await import(pathToFileURL(bindingPath));
41-
assert.strictEqual(ns.default, bindingRequire);
42-
43-
// As same as ESM-import-CJS, the default export is the value of `module.exports`.
44-
assert.strictEqual(ns.default, ns['module.exports']);
45-
assert.strictEqual(ns.default.default(), 'hello world');
46-
}
47-
48-
// binding-export-primitive.node
49-
{
50-
const bindingPath = require.resolve(`./build/${buildType}/binding-export-primitive.node`);
51-
const ns = await import(pathToFileURL(bindingPath));
52-
53-
// As same as ESM-import-CJS, the default export is the value of `module.exports`.
54-
assert.strictEqual(ns.default, ns['module.exports']);
55-
assert.strictEqual(ns.default, 'hello world');
56-
}
5734
}

0 commit comments

Comments
 (0)